/// Écran d'édition des impacts — PLEIN ÉCRAN dédié au zoom et au placement.
///
/// Cet écran est volontairement minimal : un Scaffold dont le body est
/// directement un InteractiveViewer (sans SingleScrollView ni AspectRatio
/// contraint autour). C'est la configuration la plus fiable pour le pinch :
/// l'InteractiveViewer reçoit les deux doigts sans concurrence avec un
/// scroll vertical ou une transformation parente.
///
/// Interactions :
///   - Tap sur zone vide      -> ajoute un impact
///   - Tap sur un impact      -> ouvre l'édition (score / suppression)
///   - Appui long + glisser   -> déplace l'impact
///
/// L'état des impacts est partagé avec l'écran d'analyse via le MÊME
/// AnalysisProvider (passé en ChangeNotifierProvider.value côté appelant).
library;

import 'dart:io';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../../data/models/shot.dart';
import 'analysis_provider.dart';
import 'widgets/target_overlay.dart';

class ImpactEditorScreen extends StatefulWidget {
  const ImpactEditorScreen({super.key});

  @override
  State<ImpactEditorScreen> createState() => _ImpactEditorScreenState();
}

class _ImpactEditorScreenState extends State<ImpactEditorScreen> {
  final TransformationController _transformationController =
  TransformationController();
  final GlobalKey _imageKey = GlobalKey();

  double _currentZoomScale = 1.0;
  String? _movingShotId;

  @override
  void initState() {
    super.initState();
    _transformationController.addListener(_onTransformChanged);
  }

  @override
  void dispose() {
    _transformationController.removeListener(_onTransformChanged);
    _transformationController.dispose();
    super.dispose();
  }

  void _onTransformChanged() {
    final scale = _transformationController.value.getMaxScaleOnAxis();
    if (scale != _currentZoomScale) {
      setState(() => _currentZoomScale = scale);
    }
  }

  /// Convertit une position globale en coordonnées relatives (0..1) sur l'image.
  Offset? _toImageRelative(Offset globalPosition) {
    final RenderBox? box =
    _imageKey.currentContext?.findRenderObject() as RenderBox?;
    if (box == null) return null;
    final local = box.globalToLocal(globalPosition);
    final relX = (local.dx / box.size.width).clamp(0.0, 1.0);
    final relY = (local.dy / box.size.height).clamp(0.0, 1.0);
    return Offset(relX, relY);
  }

  /// Renvoie l'impact le plus proche de [rel] dans la tolérance, sinon null.
  Shot? _hitTestShot(AnalysisProvider provider, Offset rel,
      {double tolerance = 0.04}) {
    Shot? closest;
    double minDistance = double.infinity;
    for (final shot in provider.shots) {
      final dx = shot.x - rel.dx;
      final dy = shot.y - rel.dy;
      final distance = math.sqrt(dx * dx + dy * dy);
      if (distance < minDistance && distance < tolerance) {
        minDistance = distance;
        closest = shot;
      }
    }
    return closest;
  }

  @override
  Widget build(BuildContext context) {
    final provider = context.watch<AnalysisProvider>();

    return Scaffold(
      backgroundColor: Colors.black,
      appBar: AppBar(
        backgroundColor: Colors.black,
        title: Text('Placement des impacts (${provider.shotCount})'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          tooltip: 'Retour à la calibration',
          onPressed: () => Navigator.pop(context, false),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context, true),
            child: const Text(
              'VALIDER',
              style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
            ),
          ),
        ],
      ),
      body: Column(
        children: [
          // Bandeau d'aide compact
          Container(
            width: double.infinity,
            color: Colors.white10,
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: const Text(
              'Tap : ajouter • Tap sur impact : éditer • Appui long : déplacer • Pincer : zoomer',
              style: TextStyle(color: Colors.white70, fontSize: 12),
              textAlign: TextAlign.center,
            ),
          ),

          // Zone image plein écran : InteractiveViewer dans un body nu.
          Expanded(
            child: InteractiveViewer(
              transformationController: _transformationController,
              minScale: 1.0,
              maxScale: 12.0,
              boundaryMargin: const EdgeInsets.all(80),
              panEnabled: _movingShotId == null,
              child: Center(
                child: GestureDetector(
                  behavior: HitTestBehavior.opaque,
                  // TAP : éditer si on touche un impact, sinon ajouter.
                  onTapUp: (details) {
                    if (_movingShotId != null) return;
                    final rel = _toImageRelative(details.globalPosition);
                    if (rel == null) return;

                    final hit = _hitTestShot(provider, rel);
                    if (hit != null) {
                      _showShotDetails(context, provider, hit);
                    } else {
                      provider.addShot(rel.dx, rel.dy);
                    }
                  },
                  // APPUI LONG : on saisit l'impact le plus proche pour le déplacer.
                  onLongPressStart: (details) {
                    final rel = _toImageRelative(details.globalPosition);
                    if (rel == null) return;
                    final hit = _hitTestShot(provider, rel, tolerance: 0.06);
                    if (hit != null) {
                      setState(() => _movingShotId = hit.id);
                    }
                  },
                  onLongPressMoveUpdate: (details) {
                    if (_movingShotId == null) return;
                    // Décalage pour que l'impact reste visible au-dessus du doigt.
                    final adjusted =
                        details.globalPosition + const Offset(-25, -35);
                    final rel = _toImageRelative(adjusted);
                    if (rel == null) return;
                    provider.updateShotPosition(
                        _movingShotId!, rel.dx, rel.dy);
                  },
                  onLongPressEnd: (_) {
                    if (_movingShotId != null) {
                      setState(() => _movingShotId = null);
                    }
                  },
                  child: Stack(
                    children: [
                      Image.file(
                        File(provider.imagePath!),
                        key: _imageKey,
                        fit: BoxFit.contain,
                      ),
                      Positioned.fill(
                        child: TargetOverlay(
                          targetCenterX: provider.targetCenterX,
                          targetCenterY: provider.targetCenterY,
                          targetRadius: provider.targetRadius,
                          targetType: provider.targetType!,
                          shots: provider.shots,
                          showRings: true,
                          zoomScale: _currentZoomScale,
                          // L'ajout et la sélection sont gérés par le
                          // GestureDetector parent ci-dessus.
                          onShotTapped: (shot) =>
                              _showShotDetails(context, provider, shot),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  void _showShotDetails(
      BuildContext context,
      AnalysisProvider provider,
      Shot shot,
      ) {
    showModalBottomSheet(
      context: context,
      builder: (context) => Container(
        padding: const EdgeInsets.all(24),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              'Impact #${provider.shots.indexOf(shot) + 1}',
              style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
            ),
            Text(
              'ID: ${shot.id}',
              style: Theme.of(context)
                  .textTheme
                  .bodySmall
                  ?.copyWith(color: Colors.grey, fontSize: 10),
            ),
            const SizedBox(height: 16),
            ListTile(
              leading: const Icon(Icons.score),
              title: const Text('Modifier le score'),
              trailing: DropdownButton<int>(
                value: shot.score.clamp(0, 10),
                items: List.generate(11, (index) => index)
                    .map(
                      (s) => DropdownMenuItem(
                    value: s,
                    child: Text(
                      '$s',
                      style: const TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 18,
                      ),
                    ),
                  ),
                )
                    .toList(),
                onChanged: (newScore) {
                  if (newScore != null) {
                    provider.updateShotScore(shot.id, newScore);
                    Navigator.pop(context);
                  }
                },
              ),
            ),
            const SizedBox(height: 24),
            Row(
              children: [
                Expanded(
                  child: OutlinedButton.icon(
                    onPressed: () {
                      provider.removeShot(shot.id);
                      Navigator.pop(context);
                    },
                    icon: const Icon(Icons.delete, color: Colors.red),
                    label: const Text(
                      'SUPPRIMER',
                      style: TextStyle(color: Colors.red),
                    ),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}