import 'dart:io';
import 'dart:typed_data';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:path/path.dart' as path;
import 'package:image/image.dart' as img;
import 'error_service.dart';

class StorageService {
  final FirebaseStorage _storage;
  final ErrorService _errorService;

  StorageService({
    FirebaseStorage? storage,
    ErrorService? errorService,
  }) : _storage = storage ?? FirebaseStorage.instance,
       _errorService = errorService ?? ErrorService();

  /// Upload d'une image de reçu pour une dépense
  Future<String> uploadReceiptImage(String groupId, File imageFile) async {
    try {
      // Validation du fichier
      _validateImageFile(imageFile);

      // Compression de l'image
      final compressedImage = await _compressImage(imageFile);

      // Génération du nom de fichier unique
      final fileName = _generateReceiptFileName(groupId);

      // Référence vers le storage
      final storageRef = _storage.ref().child('receipts/$groupId/$fileName');

      // Métadonnées pour optimiser le cache et la compression
      final metadata = SettableMetadata(
        contentType: 'image/jpeg',
        customMetadata: {
          'groupId': groupId,
          'uploadedAt': DateTime.now().toIso8601String(),
          'compressed': 'true',
        },
      );

      // Upload du fichier
      final uploadTask = storageRef.putData(compressedImage, metadata);

      // Monitoring du progrès (optionnel)
      uploadTask.snapshotEvents.listen((TaskSnapshot snapshot) {
        final progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        _errorService.logInfo('StorageService', 'Upload progress: ${progress.toStringAsFixed(1)}%');
      });

      // Attendre la completion
      final snapshot = await uploadTask;

      // Récupérer l'URL de téléchargement
      final downloadUrl = await snapshot.ref.getDownloadURL();

      _errorService.logSuccess('StorageService', 'Image uploadée avec succès: $fileName');
      return downloadUrl;

    } catch (e) {
      _errorService.logError('StorageService', 'Erreur upload image: $e');
      rethrow;
    }
  }

  /// Supprimer une image de reçu
  Future<void> deleteReceiptImage(String imageUrl) async {
    try {
      if (imageUrl.isEmpty) return;

      // Extraire la référence depuis l'URL
      final ref = _storage.refFromURL(imageUrl);
      await ref.delete();

      _errorService.logSuccess('StorageService', 'Image supprimée avec succès');
    } catch (e) {
      _errorService.logError('StorageService', 'Erreur suppression image: $e');
      // Ne pas rethrow pour éviter de bloquer la suppression de la dépense
    }
  }

  /// Compresser une image pour optimiser le stockage
  Future<Uint8List> _compressImage(File imageFile) async {
    try {
      // Lire l'image
      final bytes = await imageFile.readAsBytes();
      img.Image? image = img.decodeImage(bytes);

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

      // Redimensionner si l'image est trop grande
      const maxWidth = 1024;
      const maxHeight = 1024;

      if (image.width > maxWidth || image.height > maxHeight) {
        image = img.copyResize(
          image,
          width: image.width > image.height ? maxWidth : null,
          height: image.height > image.width ? maxHeight : null,
          interpolation: img.Interpolation.linear,
        );
      }

      // Encoder en JPEG avec compression
      final compressedBytes = img.encodeJpg(image, quality: 85);
      
      _errorService.logInfo('StorageService', 
        'Image compressée: ${bytes.length} → ${compressedBytes.length} bytes');

      return Uint8List.fromList(compressedBytes);
    } catch (e) {
      _errorService.logError('StorageService', 'Erreur compression image: $e');
      // Fallback: retourner l'image originale si la compression échoue
      return await imageFile.readAsBytes();
    }
  }

  /// Valider le fichier image
  void _validateImageFile(File imageFile) {
    // Vérifier que le fichier existe
    if (!imageFile.existsSync()) {
      throw Exception('Le fichier image n\'existe pas');
    }

    // Vérifier la taille du fichier (max 10MB)
    const maxSizeBytes = 10 * 1024 * 1024; // 10MB
    final fileSize = imageFile.lengthSync();
    if (fileSize > maxSizeBytes) {
      throw Exception('La taille du fichier dépasse 10MB');
    }

    // Vérifier l'extension
    final extension = path.extension(imageFile.path).toLowerCase();
    const allowedExtensions = ['.jpg', '.jpeg', '.png', '.webp'];
    if (!allowedExtensions.contains(extension)) {
      throw Exception('Format d\'image non supporté. Utilisez JPG, PNG ou WebP');
    }
  }

  /// Générer un nom de fichier unique pour un reçu
  String _generateReceiptFileName(String groupId) {
    final timestamp = DateTime.now().millisecondsSinceEpoch;
    final random = DateTime.now().microsecond;
    return 'receipt_${groupId}_${timestamp}_$random.jpg';
  }

  /// Upload multiple d'images (pour futures fonctionnalités)
  Future<List<String>> uploadMultipleImages(
    String groupId, 
    List<File> imageFiles,
  ) async {
    final uploadTasks = imageFiles.map((file) => uploadReceiptImage(groupId, file));
    return await Future.wait(uploadTasks);
  }

  /// Récupérer les métadonnées d'une image
  Future<FullMetadata?> getImageMetadata(String imageUrl) async {
    try {
      final ref = _storage.refFromURL(imageUrl);
      return await ref.getMetadata();
    } catch (e) {
      _errorService.logError('StorageService', 'Erreur récupération metadata: $e');
      return null;
    }
  }

  /// Nettoyer les images orphelines d'un groupe
  Future<void> cleanupGroupImages(String groupId) async {
    try {
      final groupRef = _storage.ref().child('receipts/$groupId');
      final listResult = await groupRef.listAll();

      for (final ref in listResult.items) {
        // Vérifier l'âge du fichier
        final metadata = await ref.getMetadata();
        final uploadDate = metadata.timeCreated;
        
        if (uploadDate != null) {
          final daysSinceUpload = DateTime.now().difference(uploadDate).inDays;
          
          // Supprimer les fichiers de plus de 30 jours sans dépense associée
          if (daysSinceUpload > 30) {
            await ref.delete();
            _errorService.logInfo('StorageService', 'Image orpheline supprimée: ${ref.name}');
          }
        }
      }
    } catch (e) {
      _errorService.logError('StorageService', 'Erreur nettoyage images: $e');
    }
  }

  /// Calculer la taille totale utilisée par un groupe
  Future<int> getGroupStorageSize(String groupId) async {
    try {
      final groupRef = _storage.ref().child('receipts/$groupId');
      final listResult = await groupRef.listAll();
      
      int totalSize = 0;
      for (final ref in listResult.items) {
        final metadata = await ref.getMetadata();
        totalSize += metadata.size ?? 0;
      }
      
      return totalSize;
    } catch (e) {
      _errorService.logError('StorageService', 'Erreur calcul taille storage: $e');
      return 0;
    }
  }
}