/// Overlay visuel de la cible.
///
/// Dessine les anneaux de la cible, les impacts et le cercle de groupement.
/// Gère uniquement la SÉLECTION d'impacts existants (tap sur un impact).
/// L'AJOUT d'un impact est délégué à l'écran parent pour éviter tout conflit
/// de gestes avec le zoom/pan de l'InteractiveViewer.
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 double? groupingCenterX;
  final double? groupingCenterY;
  final double? groupingDiameter;
  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.groupingCenterX,
    this.groupingCenterY,
    this.groupingDiameter,
    this.zoomScale = 1.0,
    this.showRings = false,
  });

  @override
  Widget build(BuildContext context) {
    // IMPORTANT : plus de GestureDetector global ici.
    // L'ancien GestureDetector (onTapUp couvrant toute la surface, en
    // HitTestBehavior.translucent) volait les pointeurs au pinch de
    // l'InteractiveViewer parent et rendait le zoom capricieux.
    //
    // Désormais :
    //  - L'AJOUT d'impact est géré par le GestureDetector parent (analysis_screen).
    //  - Seule la SÉLECTION d'un impact existant est gérée ici, via des petites
    //    zones de tap localisées (deferToChild) placées sur chaque impact.
    return IgnorePointer(
      ignoring: false,
      child: CustomPaint(
        painter: _TargetOverlayPainter(
          shots: shots,
          targetCenterX: targetCenterX,
          targetCenterY: targetCenterY,
          targetRadius: targetRadius,
          targetType: targetType,
          ringCount: ringCount,
          ringRadii: ringRadii,
          groupingCenterX: groupingCenterX,
          groupingCenterY: groupingCenterY,
          groupingDiameter: groupingDiameter,
          zoomScale: zoomScale,
          showRings: showRings,
        ),
        child: LayoutBuilder(
          builder: (context, constraints) {
            return Stack(
              children: shots.map((shot) {
                final x = shot.x * constraints.maxWidth;
                final y = shot.y * constraints.maxHeight;
                // Zone de tap qui reste constante à l'écran malgré le zoom.
                final tapSize = 30 / zoomScale;
                final halfTapSize = tapSize / 2;
                return Positioned(
                  left: x - halfTapSize,
                  top: y - halfTapSize,
                  child: GestureDetector(
                    // deferToChild : ne capte le toucher QUE sur la zone du
                    // Container (un cercle opaque au hit-test), pas ailleurs.
                    // Le reste de la surface reste donc disponible pour le
                    // pinch/pan de l'InteractiveViewer.
                    behavior: HitTestBehavior.deferToChild,
                    onTap: () => onShotTapped?.call(shot),
                    child: Container(
                      width: tapSize,
                      height: tapSize,
                      decoration: const BoxDecoration(
                        // Opaque pour le hit-test (couleur transparente visuellement
                        // mais non nulle), pour que le tap soit bien capté ici.
                        color: Color(0x01000000),
                        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 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.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);
    }
  }

  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 30% pour voir l'impact réel derrière
    final impactPaint = Paint()
      ..color = AppTheme.impactColor.withValues(alpha: 0.3)
      ..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),
    );
  }

  @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 ||
        zoomScale != oldDelegate.zoomScale ||
        showRings != oldDelegate.showRings;
  }
}