import 'dart:io';
import 'dart:math' as math;
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:camera/camera.dart';

import 'package:provider/provider.dart';
import '../../core/constants/app_constants.dart';
import '../../core/theme/app_theme.dart';
import '../../data/models/target_type.dart';
import '../crop/crop_screen.dart';
import '../session/session_provider.dart';
import 'widgets/image_source_button.dart';
import '../../services/image_crop_service.dart';
import '../../services/opencv_target_service.dart';
import '../../services/parallelism_service.dart'; // NOUVEAU
import '../../services/target_rectify_service.dart'; // NOUVEAU : redressement
import 'package:image/image.dart' as img;
import 'package:path_provider/path_provider.dart';

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

  @override
  State<CaptureScreen> createState() => _CaptureScreenState();
}

class _CaptureScreenState extends State<CaptureScreen>
    with SingleTickerProviderStateMixin {
  final ImagePicker _picker = ImagePicker();
  final ImageCropService _cropService = ImageCropService();
  final TargetType _selectedType = TargetType.concentric;
  final OpenCVTargetService _opencvService = OpenCVTargetService();

  // NOUVEAU : Service IMU de parallélisme
  final ParallelismService _parallelismService = ParallelismService(
    alignThreshold: 25.0,    // Seuil pour passer au vert (permissif)
    misalignThreshold: 32.0, // Seuil pour repasser à l'orange
  );

  String? _selectedImagePath;
  bool _isLoading = false;

  // Caméra live
  CameraController? _cameraController;
  List<CameraDescription>? _cameras;
  bool _isCameraInitialized = false;
  bool _showLiveCamera = false;

  // Animation pulsation du viseur
  late AnimationController _scanAnimationController;
  late Animation<double> _scanAnimation;

  // Détection OpenCV (cible circulaire) — on garde le résultat COMPLET
  bool? _alignmentStatus;
  TargetDetectionResult? _targetResult; // NOUVEAU : centre + rayon de la cible
  Timer? _detectionTimer;
  bool _isAnalyzingFrame = false;

  // NOUVEAU : Données IMU en temps réel
  ParallelismData? _parallelismData;
  StreamSubscription<ParallelismData>? _parallelismSubscription;

  // Service de redressement de cible (warp perspective)
  final TargetRectifyService _rectifyService = TargetRectifyService();

  @override
  void initState() {
    super.initState();
    _scanAnimationController = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat(reverse: true);

    _scanAnimation = Tween<double>(begin: 0.8, end: 1.0).animate(
      CurvedAnimation(parent: _scanAnimationController, curve: Curves.easeInOut),
    );
  }

  @override
  void dispose() {
    _cameraController?.dispose();
    _scanAnimationController.dispose();
    _detectionTimer?.cancel();
    _parallelismSubscription?.cancel(); // NOUVEAU
    _parallelismService.dispose();      // NOUVEAU
    super.dispose();
  }

  // ─────────────────────────────────────────────────────────────────────────
  // NOUVEAU : Démarre l'écoute IMU et met à jour l'UI en temps réel
  // ─────────────────────────────────────────────────────────────────────────
  void _startParallelismDetection() {
    _parallelismSubscription?.cancel();
    _parallelismService.start();

    _parallelismSubscription = _parallelismService.stream.listen((data) {
      if (mounted && _showLiveCamera) {
        setState(() {
          _parallelismData = data;
        });
      }
    });
  }

  void _stopParallelismDetection() {
    _parallelismSubscription?.cancel();
    _parallelismSubscription = null;
    _parallelismService.stop();
    _parallelismData = null;
  }

  // ─────────────────────────────────────────────────────────────────────────
  // Calcule la couleur et le message depuis l'IMU + la détection de cible
  // ─────────────────────────────────────────────────────────────────────────

  /// La cible circulaire est-elle détectée et raisonnablement cadrée ?
  bool get _targetReady {
    final t = _targetResult;
    if (t == null || !t.success) return false;
    final bool centered =
        t.centerX > 0.15 && t.centerX < 0.85 && t.centerY > 0.15 && t.centerY < 0.85;
    final bool bigEnough = t.radius > 0.12;
    return centered && bigEnough;
  }

  /// Couleur du cadre : dépend UNIQUEMENT du parallélisme IMU.
  /// (La détection de cible sert seulement à dessiner le cercle, elle ne
  ///  bloque jamais le passage au vert.)
  Color get _frameColor {
    final bool imuAligned =
        _parallelismData == null || _parallelismData!.isAligned;
    return imuAligned ? const Color(0xFF00FF00) : Colors.orange;
  }

  /// Message d'aide selon le parallélisme IMU.
  String get _alignmentMessage {
    if (_parallelismData == null ||
        _parallelismData!.status == ParallelismStatus.unknown) {
      return 'ALIGNEZ LA CIBLE DANS LE CADRE';
    }

    // Aligné → message de validation (avec bonus si la cible est détectée)
    if (_parallelismData!.isAligned) {
      return _targetReady
          ? 'PARFAIT — CIBLE DÉTECTÉE, PRÊT'
          : 'PARALLÈLE OK — PRÊT À PHOTOGRAPHIER';
    }

    // Mal aligné → message directif selon l'axe le plus dévié
    final double pitch = _parallelismData!.pitchDegrees;
    final double roll = _parallelismData!.rollDegrees;

    if (pitch.abs() >= roll.abs()) {
      return pitch > 0
          ? 'INCLINEZ VERS L\'AVANT (${pitch.toStringAsFixed(1)}°)'
          : 'INCLINEZ VERS L\'ARRIÈRE (${(-pitch).toStringAsFixed(1)}°)';
    } else {
      return roll > 0
          ? 'INCLINEZ VERS LA GAUCHE (${roll.toStringAsFixed(1)}°)'
          : 'INCLINEZ VERS LA DROITE (${(-roll).toStringAsFixed(1)}°)';
    }
  }

  // ─────────────────────────────────────────────────────────────────────────
  // Initialisation de la caméra (inchangée, sauf ajout IMU)
  // ─────────────────────────────────────────────────────────────────────────
  Future<void> _initLiveCamera() async {
    final status = await Permission.camera.request();
    if (!status.isGranted) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Accès à l\'appareil photo requis')),
        );
      }
      return;
    }

    setState(() => _isLoading = true);
    try {
      if (_cameraController != null) {
        await _cameraController!.dispose();
        _cameraController = null;
        _isCameraInitialized = false;
      }

      _cameras = await availableCameras();
      if (_cameras != null && _cameras!.isNotEmpty) {
        _cameraController = CameraController(
          _cameras![0],
          ResolutionPreset.max,
          enableAudio: false,
          imageFormatGroup: ImageFormatGroup.jpeg,
        );

        await _cameraController!.initialize();

        setState(() {
          _isCameraInitialized = true;
          _showLiveCamera = true;
          _alignmentStatus = null;
          _targetResult = null; // reset détection cible
          _parallelismData = null; // NOUVEAU : reset IMU
        });

        _startAlignmentDetection();
        _startParallelismDetection(); // NOUVEAU
      }
    } catch (e) {
      debugPrint('Erreur caméra: $e');
    } finally {
      setState(() => _isLoading = false);
    }
  }

  // ─────────────────────────────────────────────────────────────────────────
  // Détection OpenCV périodique (inchangée)
  // ─────────────────────────────────────────────────────────────────────────
  void _startAlignmentDetection() {
    _detectionTimer?.cancel();
    _detectionTimer = null;

    DateTime? _lastAnalysis;

    _cameraController!.startImageStream((CameraImage cameraImage) async {
      if (_isAnalyzingFrame) return;
      final now = DateTime.now();
      // Cadence ~1 s : assez réactif pour suivre la cible sans saturer le CPU.
      if (_lastAnalysis != null &&
          now.difference(_lastAnalysis!).inMilliseconds < 1000) return;
      _lastAnalysis = now;
      _isAnalyzingFrame = true;

      try {
        final tempDir = await getTemporaryDirectory();
        final tempPath = '${tempDir.path}/frame_analysis.jpg';

        final img.Image? converted = _convertCameraImage(cameraImage);
        if (converted == null) {
          _isAnalyzingFrame = false;
          return;
        }

        await File(tempPath).writeAsBytes(img.encodeJpg(converted, quality: 60));

        final result = await _opencvService.detectTarget(tempPath);

        try {
          await File(tempPath).delete();
        } catch (_) {}

        if (mounted && _showLiveCamera) {
          setState(() {
            // On garde le résultat complet pour dessiner le cercle.
            _targetResult = result.success ? result : null;

            if (!result.success) {
              _alignmentStatus = null;
            } else {
              final bool isCentered =
                  result.centerX > 0.25 && result.centerX < 0.75 &&
                      result.centerY > 0.25 && result.centerY < 0.75;
              final bool isSizedCorrectly = result.radius > 0.15;
              _alignmentStatus = isCentered && isSizedCorrectly;
            }
          });
        }
      } catch (e) {
        debugPrint('Erreur analyse frame: $e');
      } finally {
        _isAnalyzingFrame = false;
      }
    });
  }

  void _stopAlignmentDetection() {
    _detectionTimer?.cancel();
    _detectionTimer = null;
    try {
      if (_cameraController != null &&
          _cameraController!.value.isStreamingImages) {
        _cameraController!.stopImageStream();
      }
    } catch (_) {}
    _alignmentStatus = null;
    _targetResult = null;
  }

  img.Image? _convertCameraImage(CameraImage cameraImage) {
    try {
      final int width = cameraImage.width;
      final int height = cameraImage.height;
      final int targetW = width ~/ 2;
      final int targetH = height ~/ 2;

      final yPlane = cameraImage.planes[0];
      final uPlane = cameraImage.planes[1];
      final vPlane = cameraImage.planes[2];

      final image = img.Image(width: targetW, height: targetH);

      for (int y = 0; y < targetH; y++) {
        for (int x = 0; x < targetW; x++) {
          final int srcX = x * 2;
          final int srcY = y * 2;

          final int yIndex = srcY * yPlane.bytesPerRow + srcX;
          final int uvIndex = (srcY ~/ 2) * uPlane.bytesPerRow +
              (srcX ~/ 2) * uPlane.bytesPerPixel!;

          final int yVal = yPlane.bytes[yIndex];
          final int uVal = uPlane.bytes[uvIndex] - 128;
          final int vVal = vPlane.bytes[uvIndex] - 128;

          final int r = (yVal + 1.402 * vVal).clamp(0, 255).toInt();
          final int g = (yVal - 0.344136 * uVal - 0.714136 * vVal)
              .clamp(0, 255)
              .toInt();
          final int b = (yVal + 1.772 * uVal).clamp(0, 255).toInt();

          image.setPixelRgb(x, y, r, g, b);
        }
      }

      return image;
    } catch (e) {
      debugPrint('Erreur conversion frame: $e');
      return null;
    }
  }

  // ─────────────────────────────────────────────────────────────────────────
  // Galerie (inchangée)
  // ─────────────────────────────────────────────────────────────────────────
  Future<void> _handleGallerySelection() async {
    PermissionStatus status;

    if (Platform.isAndroid) {
      final deviceInfo = DeviceInfoPlugin();
      final androidInfo = await deviceInfo.androidInfo;
      status = androidInfo.version.sdkInt >= 33
          ? await Permission.photos.request()
          : await Permission.storage.request();
    } else {
      status = await Permission.photos.request();
    }

    if (status.isGranted) {
      _captureImageFromGallery();
    } else if (status.isPermanentlyDenied) {
      _showSettingsDialog();
    } else {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('Accès à la galerie requis pour continuer'),
          ),
        );
      }
    }
  }

  void _showSettingsDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Permission requise'),
        content: const Text(
          'L\'accès aux photos est nécessaire. Veuillez l\'activer dans les paramètres.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Annuler'),
          ),
          TextButton(
            onPressed: () => openAppSettings(),
            child: const Text('Paramètres'),
          ),
        ],
      ),
    );
  }

  // ─────────────────────────────────────────────────────────────────────────
  // Build principal
  // ─────────────────────────────────────────────────────────────────────────
  @override
  Widget build(BuildContext context) {
    final sessionProvider = context.watch<SessionProvider>();
    final title = sessionProvider.isSessionActive
        ? 'Cible ${sessionProvider.targetCount + 1}'
        : 'Source';

    if (_showLiveCamera &&
        _cameraController != null &&
        _cameraController!.value.isInitialized) {
      return _buildLiveCameraView();
    }

    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(AppConstants.defaultPadding),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            const SizedBox(height: AppConstants.largePadding),
            _buildSectionTitle('Source de l\'Image'),
            const SizedBox(height: 12),
            Row(
              children: [
                Expanded(
                  child: ImageSourceButton(
                    icon: Icons.camera_alt,
                    label: 'Scanner',
                    onPressed: _isLoading ? null : _initLiveCamera,
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: ImageSourceButton(
                    icon: Icons.photo_library,
                    label: 'Galerie',
                    onPressed: _isLoading ? null : _handleGallerySelection,
                  ),
                ),
              ],
            ),
            const SizedBox(height: AppConstants.largePadding),
            if (_isLoading)
              const Center(
                child: Padding(
                  padding: EdgeInsets.all(32),
                  child: CircularProgressIndicator(),
                ),
              )
            else
              _buildGuide(),
          ],
        ),
      ),
    );
  }

  // ─────────────────────────────────────────────────────────────────────────
  // Vue caméra live — MODIFIÉE pour utiliser les données IMU
  // ─────────────────────────────────────────────────────────────────────────
  Widget _buildLiveCameraView() {
    // Priorité : IMU (parallélisme physique) prime sur OpenCV (centrage)
    // Si l'IMU dit "mal aligné" → orange, sinon → vert
    final Color frameColor = _frameColor;
    final String alignmentMessage = _alignmentMessage;

    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(
        fit: StackFit.expand,
        children: [
          // 1. Flux vidéo caméra
          Center(
            child: AspectRatio(
              aspectRatio: 3 / 4,
              child: CameraPreview(_cameraController!),
            ),
          ),

          // 1.bis Cercle dessiné autour de la cible circulaire détectée
          if (_targetResult != null && _targetResult!.success)
            Center(
              child: AspectRatio(
                aspectRatio: 3 / 4,
                child: CustomPaint(
                  painter: _TargetCirclePainter(
                    target: _targetResult!,
                    color: _targetReady ? frameColor : Colors.white,
                    highlighted: _targetReady,
                  ),
                ),
              ),
            ),

          // 2. Cadre de visée avec coins et mire centrale
          Center(
            child: Container(
              width: MediaQuery.of(context).size.width * 0.85,
              height: MediaQuery.of(context).size.width * 0.85,
              decoration: BoxDecoration(
                border: Border.all(color: frameColor, width: 2.0),
                borderRadius: BorderRadius.circular(16),
              ),
              child: Stack(
                children: [
                  _buildCameraCorner(TopLeft: true, color: frameColor),
                  _buildCameraCorner(TopRight: true, color: frameColor),
                  _buildCameraCorner(BottomLeft: true, color: frameColor),
                  _buildCameraCorner(BottomRight: true, color: frameColor),
                  Center(
                    child: Container(
                      width: 24,
                      height: 24,
                      decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        border: Border.all(color: frameColor, width: 1.2),
                      ),
                      child: Stack(
                        children: [
                          Center(
                            child: Container(
                              width: 20,
                              height: 1.2,
                              color: frameColor,
                            ),
                          ),
                          Center(
                            child: Container(
                              width: 1.2,
                              height: 20,
                              color: frameColor,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),

          // 3. Bouton retour
          Positioned(
            top: 40,
            left: 20,
            child: CircleAvatar(
              backgroundColor: Colors.black54,
              child: IconButton(
                icon: const Icon(Icons.arrow_back, color: Colors.white),
                onPressed: () {
                  _stopAlignmentDetection();
                  _stopParallelismDetection(); // NOUVEAU
                  setState(() {
                    _showLiveCamera = false;
                  });
                },
              ),
            ),
          ),

          // 4. Message d'alignement principal (texte dynamique IMU)
          Positioned(
            top: 50,
            left: 0,
            right: 0,
            child: Center(
              child: Container(
                padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                decoration: BoxDecoration(
                  color: Colors.black.withValues(alpha: 0.7),
                  borderRadius: BorderRadius.circular(20),
                ),
                child: Text(
                  alignmentMessage,
                  style: TextStyle(
                    color: frameColor,
                    fontWeight: FontWeight.bold,
                    fontSize: 12,
                    letterSpacing: 1.2,
                  ),
                ),
              ),
            ),
          ),

          // NOUVEAU : Indicateur visuel des angles en bas à gauche
          if (_parallelismData != null &&
              _parallelismData!.status != ParallelismStatus.unknown)
            Positioned(
              bottom: 140,
              left: 16,
              child: _buildAngleIndicator(_parallelismData!),
            ),

          // Indicateur d'analyse en cours
          if (_isAnalyzingFrame)
            Positioned(
              top: 45,
              right: 20,
              child: Container(
                width: 10,
                height: 10,
                decoration: const BoxDecoration(
                  color: Colors.white54,
                  shape: BoxShape.circle,
                ),
              ),
            ),

          // 5. Bouton déclencheur
          Positioned(
            bottom: 40,
            left: 0,
            right: 0,
            child: Center(
              child: GestureDetector(
                onTap: _takePictureManually,
                child: Container(
                  height: 80,
                  width: 80,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    border: Border.all(color: Colors.white, width: 4),
                  ),
                  child: Center(
                    child: Container(
                      height: 64,
                      width: 64,
                      decoration: const BoxDecoration(
                        color: Colors.white,
                        shape: BoxShape.circle,
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  // ─────────────────────────────────────────────────────────────────────────
  // NOUVEAU : Widget affichant les angles pitch/roll en temps réel
  // ─────────────────────────────────────────────────────────────────────────
  Widget _buildAngleIndicator(ParallelismData data) {
    final Color color = data.isAligned ? const Color(0xFF00FF00) : Colors.orange;

    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
      decoration: BoxDecoration(
        color: Colors.black.withValues(alpha: 0.6),
        borderRadius: BorderRadius.circular(10),
        border: Border.all(color: color.withValues(alpha: 0.5), width: 1),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          _buildAngleRow(
            label: 'Pitch',
            value: data.pitchDegrees,
            color: color,
          ),
          const SizedBox(height: 2),
          _buildAngleRow(
            label: 'Roll ',
            value: data.rollDegrees,
            color: color,
          ),
        ],
      ),
    );
  }

  Widget _buildAngleRow({
    required String label,
    required double value,
    required Color color,
  }) {
    final String sign = value >= 0 ? '+' : '';
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          '$label: ',
          style: const TextStyle(
            color: Colors.white60,
            fontSize: 11,
            fontFamily: 'monospace',
          ),
        ),
        Text(
          '$sign${value.toStringAsFixed(1)}°',
          style: TextStyle(
            color: color,
            fontSize: 11,
            fontWeight: FontWeight.bold,
            fontFamily: 'monospace',
          ),
        ),
      ],
    );
  }

  // ─────────────────────────────────────────────────────────────────────────
  // Coins du cadre (inchangés)
  // ─────────────────────────────────────────────────────────────────────────
  Widget _buildCameraCorner({
    bool TopLeft = false,
    bool TopRight = false,
    bool BottomLeft = false,
    bool BottomRight = false,
    Color color = const Color(0xFF00FF00),
  }) {
    return Positioned(
      top: (TopLeft || TopRight) ? 10 : null,
      bottom: (BottomLeft || BottomRight) ? 10 : null,
      left: (TopLeft || BottomLeft) ? 10 : null,
      right: (TopRight || BottomRight) ? 10 : null,
      child: Container(
        width: 20,
        height: 20,
        decoration: BoxDecoration(
          border: Border(
            top: (TopLeft || TopRight)
                ? BorderSide(color: color, width: 4)
                : BorderSide.none,
            bottom: (BottomLeft || BottomRight)
                ? BorderSide(color: color, width: 4)
                : BorderSide.none,
            left: (TopLeft || BottomLeft)
                ? BorderSide(color: color, width: 4)
                : BorderSide.none,
            right: (TopRight || BottomRight)
                ? BorderSide(color: color, width: 4)
                : BorderSide.none,
          ),
        ),
      ),
    );
  }

  // ─────────────────────────────────────────────────────────────────────────
  // Capture manuelle (inchangée, sauf ajout stop IMU)
  // ─────────────────────────────────────────────────────────────────────────
  Future<void> _takePictureManually() async {
    if (_cameraController == null || !_cameraController!.value.isInitialized) {
      return;
    }

    setState(() => _isLoading = true);
    try {
      try {
        await _cameraController!.setZoomLevel(1.0);
      } catch (_) {}

      _stopAlignmentDetection();
      _stopParallelismDetection(); // NOUVEAU

      final XFile photo = await _cameraController!.takePicture();

      // NOUVEAU : redressement automatique de la cible (warp perspective).
      // On écrit le résultat dans un fichier dédié, à côté de l'original.
      String finalPath = photo.path;
      try {
        final tempDir = await getTemporaryDirectory();
        final rectifiedPath =
            '${tempDir.path}/rectified_${DateTime.now().millisecondsSinceEpoch}.jpg';

        final result = await _rectifyService.rectify(
          inputPath: photo.path,
          outputPath: rectifiedPath,
        );

        finalPath = result.outputPath;

        if (mounted && result.rectified) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              duration: const Duration(seconds: 2),
              content: Text(
                'Cible redressée automatiquement '
                    '(inclinaison ${result.estimatedTiltDegrees.toStringAsFixed(1)}° corrigée)',
              ),
            ),
          );
        }
      } catch (e) {
        debugPrint('Redressement ignoré: $e');
        finalPath = photo.path; // on garde la photo originale en secours
      }

      setState(() {
        _selectedImagePath = finalPath;
        _showLiveCamera = false;
      });

      _analyzeImage();
    } catch (e) {
      debugPrint('Erreur lors du clic photo: $e');
    } finally {
      setState(() => _isLoading = false);
    }
  }

  // ─────────────────────────────────────────────────────────────────────────
  // Helpers UI (inchangés)
  // ─────────────────────────────────────────────────────────────────────────
  Widget _buildSectionTitle(String title) {
    return Text(
      title,
      style: Theme.of(context)
          .textTheme
          .titleMedium
          ?.copyWith(fontWeight: FontWeight.bold),
    );
  }

  Widget _buildGuide() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(AppConstants.defaultPadding),
        child: Column(
          children: [
            Icon(Icons.help_outline, size: 48, color: Colors.grey[400]),
            const SizedBox(height: 12),
            Text(
              'Conseils pour une bonne analyse',
              style: Theme.of(context)
                  .textTheme
                  .titleSmall
                  ?.copyWith(fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 12),
            _buildGuideItem(
              Icons.crop_free,
              'Cadrez la cible entière dans l\'image',
            ),
            _buildGuideItem(Icons.wb_sunny, 'Utilisez un bon éclairage'),
            _buildGuideItem(Icons.straighten, 'Prenez la photo de face'),
            _buildGuideItem(Icons.blur_off, 'Évitez les images floues'),
            _buildGuideItem(
              Icons.cleaning_services,
              'Nettoyer votre objectif avec une chiffonnette',
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildGuideItem(IconData icon, String text) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        children: [
          Icon(icon, size: 20, color: AppTheme.primaryColor),
          const SizedBox(width: 12),
          Expanded(child: Text(text)),
        ],
      ),
    );
  }

  Future<void> _captureImageFromGallery() async {
    setState(() => _isLoading = true);
    try {
      final XFile? image = await _picker.pickImage(
        source: ImageSource.gallery,
        maxWidth: 2048,
        maxHeight: 2048,
        imageQuality: 90,
      );
      if (image != null) {
        setState(() {
          _selectedImagePath = image.path;
        });
        _analyzeImage();
      }
    } catch (e) {
      debugPrint('Erreur galerie: $e');
    } finally {
      if (mounted) setState(() => _isLoading = false);
    }
  }

  void _analyzeImage() {
    if (_selectedImagePath == null) return;

    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (_) => CropScreen(
          imagePath: _selectedImagePath!,
          targetType: _selectedType,
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────────────────────────────────
// Painter qui dessine un cercle autour de la cible circulaire détectée.
// Le centre et le rayon viennent d'OpenCV (coordonnées normalisées 0..1).
// Blanc tant que la cible n'est pas bien cadrée, couleur d'état sinon.
// ─────────────────────────────────────────────────────────────────────────
class _TargetCirclePainter extends CustomPainter {
  final TargetDetectionResult target;
  final Color color;
  final bool highlighted;

  _TargetCirclePainter({
    required this.target,
    required this.color,
    required this.highlighted,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // Centre en pixels dans la zone de dessin
    final double cx = target.centerX * size.width;
    final double cy = target.centerY * size.height;
    // radius est normalisé par min(largeur, hauteur) côté OpenCV
    final double r = target.radius * math.min(size.width, size.height);

    final Paint stroke = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = highlighted ? 3.5 : 2.0
      ..color = color;

    // Cercle principal autour de la cible
    canvas.drawCircle(Offset(cx, cy), r, stroke);

    // Petite croix au centre détecté
    final Paint cross = Paint()
      ..strokeWidth = 2.0
      ..color = color;
    const double k = 10;
    canvas.drawLine(Offset(cx - k, cy), Offset(cx + k, cy), cross);
    canvas.drawLine(Offset(cx, cy - k), Offset(cx, cy + k), cross);

    // Étiquette "CIBLE" quand elle est bien cadrée
    if (highlighted) {
      final tp = TextPainter(
        text: TextSpan(
          text: ' CIBLE ',
          style: TextStyle(
            color: Colors.black,
            fontSize: 12,
            fontWeight: FontWeight.bold,
            backgroundColor: color,
          ),
        ),
        textDirection: TextDirection.ltr,
      )..layout();
      tp.paint(canvas, Offset(cx - tp.width / 2, (cy - r - 20).clamp(0.0, size.height)));
    }
  }

  @override
  bool shouldRepaint(_TargetCirclePainter old) =>
      old.target != target ||
          old.color != color ||
          old.highlighted != highlighted;
}