/// Overlay visuel de la cible.
///
/// Dessine les anneaux de la cible, les impacts détectés, le cercle de groupement
/// et les impacts de référence. Gère les interactions tactiles pour l'ajout
/// d'impacts et la sélection d'impacts existants.
library;

import 'package:flutter/material.dart';
import '../../../core/theme/app_theme.dart';
import '../../../data/models/shot.dart';
import '../../../data/models/target_type.dart';

class TargetOverlay extends StatelessWidget {
  final List<Shot> shots;
  final double targetCenterX;
  final double targetCenterY;
  final double targetRadius;
  final TargetType targetType;
  final int ringCount;
  final List<double>? ringRadii;
  final void Function(Shot shot)? onShotTapped;
  final void Function(double x, double y)? onAddShot;
  final double? groupingCenterX;
  final double? groupingCenterY;
  final double? groupingDiameter;
  final List<Shot>? referenceImpacts;
  final double zoomScale;
  final bool showRings;

  const TargetOverlay({
    super.key,
    required this.shots,
    required this.targetCenterX,
    required this.targetCenterY,
    required this.targetRadius,
    required this.targetType,
    this.ringCount = 10,
    this.ringRadii,
    this.onShotTapped,
    this.onAddShot,
    this.groupingCenterX,
    this.groupingCenterY,
    this.groupingDiameter,
    this.referenceImpacts,
    this.zoomScale = 1.0,
    this.showRings = false,
  });

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        return GestureDetector(
          behavior: HitTestBehavior.translucent,
          onTapUp: (details) {
            if (onAddShot != null) {
              // Utiliser les constraints pour un calcul précis
              final relX = details.localPosition.dx / constraints.maxWidth;
              final relY = details.localPosition.dy / constraints.maxHeight;
              onAddShot!(relX, relY);
            }
          },
          child: CustomPaint(
            painter: _TargetOverlayPainter(
              shots: shots,
              targetCenterX: targetCenterX,
              targetCenterY: targetCenterY,
              targetRadius: targetRadius,
              targetType: targetType,
              ringCount: ringCount,
              ringRadii: ringRadii,
              groupingCenterX: groupingCenterX,
              groupingCenterY: groupingCenterY,
              groupingDiameter: groupingDiameter,
              referenceImpacts: referenceImpacts,
              zoomScale: zoomScale,
              showRings: showRings,
            ),
            child: Stack(
              children: shots.map((shot) {
                return Positioned(
                  left: 0,
                  top: 0,
                  right: 0,
                  bottom: 0,
                  child: LayoutBuilder(
                    builder: (context, innerConstraints) {
                      final x = shot.x * innerConstraints.maxWidth;
                      final y = shot.y * innerConstraints.maxHeight;
                      // Zone de tap qui s'adapte au zoom (taille fixe à l'écran)
                      final tapSize = 30 / zoomScale;
                      final halfTapSize = tapSize / 2;
                      return Stack(
                        children: [
                          Positioned(
                            left: x - halfTapSize,
                            top: y - halfTapSize,
                            child: GestureDetector(
                              behavior: HitTestBehavior.translucent,
                              onTap: () => onShotTapped?.call(shot),
                              child: Container(
                                width: tapSize,
                                height: tapSize,
                                decoration: const BoxDecoration(
                                  color: Colors.transparent,
                                  shape: BoxShape.circle,
                                ),
                              ),
                            ),
                          ),
                        ],
                      );
                    },
                  ),
                );
              }).toList(),
            ),
          ),
        );
      },
    );
  }
}

class _TargetOverlayPainter extends CustomPainter {
  final List<Shot> shots;
  final double targetCenterX;
  final double targetCenterY;
  final double targetRadius;
  final TargetType targetType;
  final int ringCount;
  final List<double>? ringRadii;
  final double? groupingCenterX;
  final double? groupingCenterY;
  final double? groupingDiameter;
  final List<Shot>? referenceImpacts;
  final double zoomScale;
  final bool showRings;

  _TargetOverlayPainter({
    required this.shots,
    required this.targetCenterX,
    required this.targetCenterY,
    required this.targetRadius,
    required this.targetType,
    this.ringCount = 10,
    this.ringRadii,
    this.groupingCenterX,
    this.groupingCenterY,
    this.groupingDiameter,
    this.referenceImpacts,
    this.zoomScale = 1.0,
    this.showRings = false,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // Draw target center indicator
    if (showRings) {
      _drawTargetCenter(canvas, size);
    }

    // Draw grouping circle
    if (groupingCenterX != null && groupingCenterY != null && groupingDiameter != null && shots.length > 1) {
      _drawGroupingCircle(canvas, size);
    }

    // Draw impacts
    for (final shot in shots) {
      _drawImpact(canvas, size, shot);
    }

    // Draw reference impacts (with different color)
    if (referenceImpacts != null) {
      for (final ref in referenceImpacts!) {
        _drawReferenceImpact(canvas, size, ref);
      }
    }
  }

  void _drawTargetCenter(Canvas canvas, Size size) {
    final centerX = targetCenterX * size.width;
    final centerY = targetCenterY * size.height;
    final minDim = size.width < size.height ? size.width : size.height;
    final maxRadius = targetRadius * minDim;

    final strokePaint = Paint()
      ..color = Colors.green.withValues(alpha: 0.5)
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1;

    // Draw concentric rings based on ringCount (with individual radii if provided)
    for (int i = 0; i < ringCount; i++) {
      final ringMultiplier = (ringRadii != null && ringRadii!.length == ringCount)
          ? ringRadii![i]
          : (i + 1) / ringCount;
      final ringRadius = maxRadius * ringMultiplier;
      canvas.drawCircle(Offset(centerX, centerY), ringRadius, strokePaint);
    }

    // Draw score labels on rings (only if within visible area)
    final textPainter = TextPainter(
      textDirection: TextDirection.ltr,
    );

    for (int i = 0; i < ringCount; i++) {
      // Calculate zone center (midpoint between this ring and previous)
      final currentMultiplier = (ringRadii != null && ringRadii!.length == ringCount)
          ? ringRadii![i]
          : (i + 1) / ringCount;
      final prevMultiplier = i == 0
          ? 0.0
          : (ringRadii != null && ringRadii!.length == ringCount)
          ? ringRadii![i - 1]
          : i / ringCount;
      final zoneRadius = maxRadius * (currentMultiplier + prevMultiplier) / 2;
      final score = 10 - i;

      // Only draw label if it's within the visible area
      final labelX = centerX + zoneRadius;
      if (labelX < 0 || labelX > size.width) continue;

      textPainter.text = TextSpan(
        text: '$score',
        style: TextStyle(
          color: Colors.green.withValues(alpha: 0.8),
          fontSize: 10,
          fontWeight: FontWeight.bold,
          shadows: const [
            Shadow(color: Colors.black, blurRadius: 2),
          ],
        ),
      );
      textPainter.layout();

      // Draw label on the right side of each zone
      final labelY = centerY - textPainter.height / 2;
      if (labelY >= 0 && labelY <= size.height) {
        textPainter.paint(canvas, Offset(labelX - textPainter.width / 2, labelY));
      }
    }

    // Draw crosshair at center
    final crosshairPaint = Paint()
      ..color = Colors.green.withValues(alpha: 0.7)
      ..strokeWidth = 1;

    canvas.drawLine(
      Offset(centerX - 10, centerY),
      Offset(centerX + 10, centerY),
      crosshairPaint,
    );
    canvas.drawLine(
      Offset(centerX, centerY - 10),
      Offset(centerX, centerY + 10),
      crosshairPaint,
    );
  }

  void _drawGroupingCircle(Canvas canvas, Size size) {
    final centerX = groupingCenterX! * size.width;
    final centerY = groupingCenterY! * size.height;
    final diameter = groupingDiameter! * size.width.clamp(0, size.height);

    // Draw filled circle
    final fillPaint = Paint()
      ..color = AppTheme.groupingCircleColor
      ..style = PaintingStyle.fill;
    canvas.drawCircle(Offset(centerX, centerY), diameter / 2, fillPaint);

    // Draw outline
    final strokePaint = Paint()
      ..color = AppTheme.groupingCenterColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;
    canvas.drawCircle(Offset(centerX, centerY), diameter / 2, strokePaint);

    // Draw center point
    final centerPaint = Paint()
      ..color = AppTheme.groupingCenterColor
      ..style = PaintingStyle.fill;
    canvas.drawCircle(Offset(centerX, centerY), 4, centerPaint);
  }

  void _drawImpact(Canvas canvas, Size size, Shot shot) {
    final x = shot.x * size.width;
    final y = shot.y * size.height;

    // Tailles fixes divisées par le zoom pour rester constantes à l'écran
    final outerRadius = 10 / zoomScale;
    final innerRadius = 8 / zoomScale;
    final strokeWidth = 3 / zoomScale;
    final fontSize = 10 / zoomScale;

    // Draw outer circle (white outline for visibility) — gardé OPAQUE pour
    // bien repérer le centre même quand le remplissage est transparent.
    final outlinePaint = Paint()
      ..color = AppTheme.impactOutlineColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;
    canvas.drawCircle(Offset(x, y), outerRadius, outlinePaint);

    // Draw impact marker — TRANSPARENCE 50% pour voir l'impact réel derrière
    final impactPaint = Paint()
      ..color = AppTheme.impactColor.withValues(alpha: 0.5)
      ..style = PaintingStyle.fill;
    canvas.drawCircle(Offset(x, y), innerRadius, impactPaint);

    // Draw score number
    final textPainter = TextPainter(
      text: TextSpan(
        text: '${shot.score}',
        style: TextStyle(
          color: Colors.white,
          fontSize: fontSize,
          fontWeight: FontWeight.bold,
        ),
      ),
      textDirection: TextDirection.ltr,
    );
    textPainter.layout();
    textPainter.paint(
      canvas,
      Offset(x - textPainter.width / 2, y - textPainter.height / 2),
    );
  }

  void _drawReferenceImpact(Canvas canvas, Size size, Shot ref) {
    final x = ref.x * size.width;
    final y = ref.y * size.height;

    // Tailles fixes divisées par le zoom pour rester constantes à l'écran
    final outerRadius = 12 / zoomScale;
    final innerRadius = 10 / zoomScale;
    final strokeWidth = 3 / zoomScale;
    final fontSize = 12 / zoomScale;

    // Draw outer circle (white outline for visibility)
    final outlinePaint = Paint()
      ..color = Colors.white
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;
    canvas.drawCircle(Offset(x, y), outerRadius, outlinePaint);

    // Draw reference marker (purple)
    final refPaint = Paint()
      ..color = Colors.deepPurple
      ..style = PaintingStyle.fill;
    canvas.drawCircle(Offset(x, y), innerRadius, refPaint);

    // Draw "R" to indicate reference
    final textPainter = TextPainter(
      text: TextSpan(
        text: 'R',
        style: TextStyle(
          color: Colors.white,
          fontSize: fontSize,
          fontWeight: FontWeight.bold,
        ),
      ),
      textDirection: TextDirection.ltr,
    );
    textPainter.layout();
    textPainter.paint(
      canvas,
      Offset(x - textPainter.width / 2, y - textPainter.height / 2),
    );
  }

  @override
  bool shouldRepaint(covariant _TargetOverlayPainter oldDelegate) {
    return shots != oldDelegate.shots ||
        targetCenterX != oldDelegate.targetCenterX ||
        targetCenterY != oldDelegate.targetCenterY ||
        targetRadius != oldDelegate.targetRadius ||
        ringCount != oldDelegate.ringCount ||
        ringRadii != oldDelegate.ringRadii ||
        groupingCenterX != oldDelegate.groupingCenterX ||
        groupingCenterY != oldDelegate.groupingCenterY ||
        groupingDiameter != oldDelegate.groupingDiameter ||
        referenceImpacts != oldDelegate.referenceImpacts ||
        zoomScale != oldDelegate.zoomScale ||
        showRings != oldDelegate.showRings;
  }
}