/// Service de recadrage d'images.
///
/// Permet de recadrer une image en format carré (1:1) et de la sauvegarder
/// dans un fichier temporaire pour utilisation ultérieure.
library;

import 'dart:io';
import 'dart:math' as math;
import 'package:image/image.dart' as img;
import 'package:path_provider/path_provider.dart';
import 'package:uuid/uuid.dart';

/// Représente une zone de recadrage normalisée (0.0 à 1.0)
class CropRect {
  /// Position X du coin supérieur gauche (0.0 à 1.0)
  final double x;

  /// Position Y du coin supérieur gauche (0.0 à 1.0)
  final double y;

  /// Largeur de la zone (0.0 à 1.0)
  final double width;

  /// Hauteur de la zone (0.0 à 1.0)
  final double height;

  const CropRect({
    required this.x,
    required this.y,
    required this.width,
    required this.height,
  });

  @override
  String toString() => 'CropRect(x: $x, y: $y, w: $width, h: $height)';
}

/// Service pour recadrer les images
class ImageCropService {
  final Uuid _uuid = const Uuid();

  /// Taille de sortie maximale pour les images recadrées
  static const int maxOutputSize = 1024;

  /// Recadre une image en format carré
  ///
  /// [sourcePath] - Chemin vers l'image source
  /// [cropRect] - Zone de recadrage normalisée (0.0 à 1.0)
  /// [outputSize] - Taille de sortie en pixels (carré)
  ///
  /// Retourne le chemin vers l'image recadrée dans le dossier temporaire
  Future<String> cropToSquare(
    String sourcePath,
    CropRect cropRect, {
    int outputSize = maxOutputSize,
  }) async {
    // Charger l'image source
    final file = File(sourcePath);
    final bytes = await file.readAsBytes();
    final originalImage = img.decodeImage(bytes);

    if (originalImage == null) {
      throw Exception('Impossible de décoder l\'image: $sourcePath');
    }

    // Calculer les coordonnées en pixels
    final srcX = (cropRect.x * originalImage.width).round();
    final srcY = (cropRect.y * originalImage.height).round();
    final srcWidth = (cropRect.width * originalImage.width).round();
    final srcHeight = (cropRect.height * originalImage.height).round();

    // S'assurer que les dimensions sont valides
    final clampedX = srcX.clamp(0, originalImage.width - 1);
    final clampedY = srcY.clamp(0, originalImage.height - 1);
    final clampedWidth = math.min(srcWidth, originalImage.width - clampedX);
    final clampedHeight = math.min(srcHeight, originalImage.height - clampedY);

    // Recadrer l'image
    img.Image cropped = img.copyCrop(
      originalImage,
      x: clampedX,
      y: clampedY,
      width: clampedWidth,
      height: clampedHeight,
    );

    // Redimensionner à la taille de sortie si nécessaire
    if (cropped.width != outputSize || cropped.height != outputSize) {
      cropped = img.copyResize(
        cropped,
        width: outputSize,
        height: outputSize,
        interpolation: img.Interpolation.cubic,
      );
    }

    // Sauvegarder dans le dossier temporaire
    final tempDir = await getTemporaryDirectory();
    final fileName = 'cropped_${_uuid.v4()}.jpg';
    final outputPath = '${tempDir.path}/$fileName';

    final outputFile = File(outputPath);
    await outputFile.writeAsBytes(img.encodeJpg(cropped, quality: 90));

    return outputPath;
  }

  /// Calcule la zone de recadrage carrée maximale centrée sur l'image
  ///
  /// [imageWidth] - Largeur de l'image en pixels
  /// [imageHeight] - Hauteur de l'image en pixels
  ///
  /// Retourne un CropRect normalisé pour un carré centré
  CropRect getDefaultSquareCrop(int imageWidth, int imageHeight) {
    final aspectRatio = imageWidth / imageHeight;

    if (aspectRatio > 1) {
      // Image plus large que haute - centrer horizontalement
      final squareWidth = imageHeight / imageWidth;
      final x = (1 - squareWidth) / 2;
      return CropRect(x: x, y: 0, width: squareWidth, height: 1);
    } else if (aspectRatio < 1) {
      // Image plus haute que large - centrer verticalement
      final squareHeight = imageWidth / imageHeight;
      final y = (1 - squareHeight) / 2;
      return CropRect(x: 0, y: y, width: 1, height: squareHeight);
    } else {
      // Déjà carré
      return const CropRect(x: 0, y: 0, width: 1, height: 1);
    }
  }

  /// Nettoie les fichiers temporaires de crop anciens
  Future<void> cleanupOldCrops({Duration maxAge = const Duration(hours: 24)}) async {
    try {
      final tempDir = await getTemporaryDirectory();
      final dir = Directory(tempDir.path);
      final now = DateTime.now();

      await for (final entity in dir.list()) {
        if (entity is File && entity.path.contains('cropped_')) {
          final stat = await entity.stat();
          final age = now.difference(stat.modified);
          if (age > maxAge) {
            await entity.delete();
          }
        }
      }
    } catch (e) {
      // Ignorer les erreurs de nettoyage
    }
  }
}
