import 'dart:async';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:geosector_app/core/data/models/operation_model.dart';
import 'package:geosector_app/core/data/models/passage_model.dart';
import 'package:geosector_app/core/data/models/sector_model.dart';
import 'package:geosector_app/core/data/models/user_sector_model.dart';
import 'package:geosector_app/core/services/api_service.dart';
import 'package:geosector_app/core/services/data_loading_service.dart';
import 'package:geosector_app/core/constants/app_keys.dart';

class OperationRepository extends ChangeNotifier {
  // Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
  // et vérifier qu'elle est ouverte avant accès
  Box<OperationModel> get _operationBox {
    _ensureBoxIsOpen();
    return Hive.box<OperationModel>(AppKeys.operationsBoxName);
  }

  // Getter exposant publiquement la Hive Box
  Box<OperationModel> get operationBox => _operationBox;

  // Méthode pour vérifier si la boîte est ouverte et l'ouvrir si nécessaire
  Future<void> _ensureBoxIsOpen() async {
    const boxName = AppKeys.operationsBoxName;
    if (!Hive.isBoxOpen(boxName)) {
      debugPrint('Ouverture de la boîte $boxName dans OperationRepository...');
      await Hive.openBox<OperationModel>(boxName);
    }
  }

  bool _isLoading = false;

  // Constructeur sans paramètres - utilise ApiService.instance
  OperationRepository();

  // Getters
  bool get isLoading => _isLoading;
  List<OperationModel> get operations => getAllOperations();

  // Récupérer toutes les opérations
  List<OperationModel> getAllOperations() {
    return _operationBox.values.toList();
  }

  // Récupérer une opération par son ID
  OperationModel? getOperationById(int id) {
    return _operationBox.get(id);
  }

  OperationModel? getCurrentOperation() {
    try {
      // Récupérer toutes les opérations actives
      final activeOperations = _operationBox.values
          .where((operation) => operation.isActive == true)
          .toList();

      if (activeOperations.isEmpty) {
        debugPrint('⚠️ Aucune opération active trouvée');
        return null;
      }

      // Trier par ID décroissant et prendre la première (ID le plus élevé)
      activeOperations.sort((a, b) => b.id.compareTo(a.id));
      final currentOperation = activeOperations.first;

      debugPrint(
          '🎯 Opération courante: ${currentOperation.id} - ${currentOperation.name}');
      return currentOperation;
    } catch (e) {
      debugPrint(
          '❌ Erreur lors de la récupération de l\'opération courante: $e');
      return null;
    }
  }

// Méthode helper pour récupérer seulement l'ID de l'opération courante
  int? getCurrentOperationId() {
    final currentOperation = getCurrentOperation();
    return currentOperation?.id;
  }

// Méthode pour récupérer toutes les opérations actives (utile pour debug/admin)
  List<OperationModel> getActiveOperations() {
    try {
      return _operationBox.values
          .where((operation) => operation.isActive == true)
          .toList()
        ..sort((a, b) => b.id.compareTo(a.id)); // Tri par ID décroissant
    } catch (e) {
      debugPrint('❌ Erreur lors de la récupération des opérations actives: $e');
      return [];
    }
  }

  // Sauvegarder une opération
  Future<void> saveOperation(OperationModel operation) async {
    await _operationBox.put(operation.id, operation);
    notifyListeners();
  }

  // Supprimer une opération
  Future<void> deleteOperation(int id) async {
    await _operationBox.delete(id);
    notifyListeners();
  }

  // Créer ou mettre à jour des opérations à partir des données de l'API
  Future<void> processOperationsFromApi(List<dynamic> operationsData) async {
    _isLoading = true;
    notifyListeners();

    try {
      debugPrint(
          '🔄 Traitement de ${operationsData.length} opérations depuis l\'API');

      for (var operationData in operationsData) {
        final operationJson = operationData as Map<String, dynamic>;
        final operationId = operationJson['id'] is String
            ? int.parse(operationJson['id'])
            : operationJson['id'] as int;

        debugPrint(
            '📝 Traitement opération ID: $operationId, libelle: ${operationJson['libelle']}');

        // Vérifier si l'opération existe déjà
        OperationModel? existingOperation = getOperationById(operationId);

        if (existingOperation == null) {
          // Créer une nouvelle opération
          final newOperation = OperationModel.fromJson(operationJson);
          await saveOperation(newOperation);
          debugPrint('✅ Nouvelle opération créée: ${newOperation.name}');
        } else {
          // Mettre à jour l'opération existante
          final updatedOperation = existingOperation.copyWith(
            name: operationJson[
                'libelle'], // ← Correction: utiliser 'libelle' au lieu de 'name'
            fkEntite: operationJson['fk_entite'],
            dateDebut: DateTime.parse(operationJson['date_deb']),
            dateFin: DateTime.parse(operationJson['date_fin']),
            isActive: operationJson['chk_active'] == true ||
                operationJson['chk_active'] == 1 ||
                operationJson['chk_active'] == "1",
            lastSyncedAt: DateTime.now(),
            isSynced: true,
          );
          await saveOperation(updatedOperation);
          debugPrint('✅ Opération mise à jour: ${updatedOperation.name}');
        }
      }

      debugPrint(
          '🎉 Traitement terminé - ${_operationBox.length} opérations dans la box');
    } catch (e) {
      debugPrint('❌ Erreur lors du traitement des opérations: $e');
      debugPrint('❌ Stack trace: ${StackTrace.current}');
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Créer une opération
  Future<bool> createOperation(
      String name, DateTime dateDebut, DateTime dateFin, {BuildContext? context}) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Préparer les données pour l'API
      final Map<String, dynamic> data = {
        'name': name,
        'date_deb':
            dateDebut.toIso8601String().split('T')[0], // Format YYYY-MM-DD
        'date_fin':
            dateFin.toIso8601String().split('T')[0], // Format YYYY-MM-DD
      };

      debugPrint('🚀 Création d\'une nouvelle opération: $data');

      // Appeler l'API pour créer l'opération
      final response =
          await ApiService.instance.post('/operations', data: data);

      // Vérifier si la requête a été mise en queue (mode offline)
      if (response.data != null && response.data['queued'] == true) {
        // Mode offline : NE PAS créer l'opération dans Hive
        debugPrint('⏳ Création de l\'opération mise en attente (mode hors ligne)');
        
        // Informer l'utilisateur si un contexte est fourni
        if (context != null && context.mounted) {
          showDialog(
            context: context,
            builder: (context) => AlertDialog(
              title: const Row(
                children: [
                  Icon(Icons.cloud_off, color: Colors.orange),
                  SizedBox(width: 8),
                  Text('Création en attente'),
                ],
              ),
              content: const Text(
                'L\'opération sera créée dès que la connexion sera rétablie.\n\n'
                'La création a été ajoutée à la file d\'attente.',
              ),
              actions: [
                TextButton(
                  onPressed: () => Navigator.of(context).pop(),
                  child: const Text('Compris'),
                ),
              ],
            ),
          );
        }
        return true; // Indiquer que l'opération a été acceptée (mise en queue)
      }

      if (response.statusCode == 201 || response.statusCode == 200) {
        debugPrint('✅ Opération créée avec succès');

        // Traiter la réponse complète de l'API
        await _processCreationResponse(response.data);
        return true;
      }

      debugPrint('❌ Échec de la création - Code: ${response.statusCode}');
      return false;
    } catch (e) {
      debugPrint('❌ Erreur lors de la création de l\'opération: $e');
      rethrow;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Traiter la réponse complète après création d'opération
  Future<void> _processCreationResponse(
      Map<String, dynamic> responseData) async {
    try {
      debugPrint('🔄 Traitement de la réponse de création d\'opération');

      // Traiter les opérations (groupe operations)
      if (responseData['operations'] != null) {
        await processOperationsFromApi(responseData['operations']);
        debugPrint('✅ Opérations traitées');
      }

      // Traiter les secteurs (groupe sectors) via DataLoadingService
      if (responseData['sectors'] != null) {
        await DataLoadingService.instance
            .processSectorsFromApi(responseData['sectors']);
        debugPrint('✅ Secteurs traités');
      }

      // Traiter les passages (groupe passages) via DataLoadingService
      if (responseData['passages'] != null) {
        await DataLoadingService.instance
            .processPassagesFromApi(responseData['passages']);
        debugPrint('✅ Passages traités');
      }

      // Traiter les users_sectors (groupe users_sectors) via DataLoadingService
      if (responseData['users_sectors'] != null) {
        await DataLoadingService.instance
            .processUserSectorsFromApi(responseData['users_sectors']);
        debugPrint('✅ Users_sectors traités');
      }

      debugPrint('🎉 Tous les groupes de données ont été traités avec succès');
    } catch (e) {
      debugPrint('❌ Erreur lors du traitement de la réponse: $e');
      // Ne pas faire échouer la création si le traitement des données supplémentaires échoue
    }
  }

  // Méthode universelle pour sauvegarder une opération (création ou mise à jour)
  Future<bool> saveOperationFromModel(OperationModel operation) async {
    debugPrint('=== saveOperationFromModel APPELÉ ===');
    debugPrint('operation.id: ${operation.id}');
    debugPrint('operation.name: ${operation.name}');

    try {
      if (operation.id == 0) {
        // Nouvelle opération - créer
        debugPrint('=== CRÉATION (POST) ===');
        return await createOperation(
          operation.name,
          operation.dateDebut,
          operation.dateFin,
          context: null, // Pas de contexte disponible ici
        );
      } else {
        // Opération existante - mettre à jour
        debugPrint('=== MISE À JOUR (PUT) ===');
        final result = await updateOperation(
          operation.id,
          name: operation.name,
          dateDebut: operation.dateDebut,
          dateFin: operation.dateFin,
          isActive: operation.isActive,
          fkEntite: operation.fkEntite, // ← Inclure fkEntite
        );
        debugPrint('=== RÉSULTAT UPDATE: $result ===');
        return result;
      }
    } catch (e) {
      debugPrint('=== ERREUR dans saveOperationFromModel: $e ===');
      // Propager l'exception pour que la page parente puisse la gérer
      rethrow;
    }
  }

  // Méthode pour mettre à jour une opération avec un objet OperationModel
  Future<bool> updateOperationFromModel(OperationModel operation) async {
    return await updateOperation(
      operation.id,
      name: operation.name,
      dateDebut: operation.dateDebut,
      dateFin: operation.dateFin,
      isActive: operation.isActive,
      fkEntite: operation.fkEntite, // ← Inclure fkEntite
    );
  }

  // Mettre à jour une opération
  Future<bool> updateOperation(int id,
      {String? name,
      DateTime? dateDebut,
      DateTime? dateFin,
      bool? isActive,
      int? fkEntite}) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Récupérer l'opération existante
      final existingOperation = getOperationById(id);
      if (existingOperation == null) {
        debugPrint('❌ Opération avec l\'ID $id non trouvée');
        throw Exception('Opération non trouvée');
      }

      // Préparer les données pour l'API
      final Map<String, dynamic> data = {
        'id': id,
        'name': name ?? existingOperation.name,
        'date_deb': (dateDebut ?? existingOperation.dateDebut)
            .toIso8601String()
            .split('T')[0],
        'date_fin': (dateFin ?? existingOperation.dateFin)
            .toIso8601String()
            .split('T')[0],
        'chk_active': isActive ??
            existingOperation.isActive, // Utiliser chk_active comme dans l'API
        'fk_entite':
            fkEntite ?? existingOperation.fkEntite, // ← Inclure fkEntite
      };

      debugPrint('🔄 Mise à jour de l\'opération $id avec les données: $data');
      // Appeler l'API pour mettre à jour l'opération
      final response =
          await ApiService.instance.put('/operations/$id', data: data);

      // Vérifier si la requête a été mise en queue (mode offline)
      if (response.data != null && response.data['queued'] == true) {
        // Mode offline : Sauvegarder localement avec indicateur
        final updatedOperation = existingOperation.copyWith(
          name: name,
          dateDebut: dateDebut,
          dateFin: dateFin,
          isActive: isActive,
          fkEntite: fkEntite,
          lastSyncedAt: null,
          isSynced: false,
        );
        await saveOperation(updatedOperation);
        debugPrint('⏳ Modification de l\'opération $id mise en attente (mode hors ligne)');
        return true;
      }

      if (response.statusCode == 200) {
        debugPrint('✅ Opération $id mise à jour avec succès');
        // Mettre à jour l'opération localement
        final updatedOperation = existingOperation.copyWith(
          name: name,
          dateDebut: dateDebut,
          dateFin: dateFin,
          isActive: isActive,
          fkEntite: fkEntite,
          lastSyncedAt: DateTime.now(),
          isSynced: true,
        );
        await saveOperation(updatedOperation);
        return true;
      } else {
        debugPrint('❌ Échec de la mise à jour - Code: ${response.statusCode}');
        throw Exception('Échec de la mise à jour de l\'opération');
      }
    } catch (e) {
      debugPrint('❌ Erreur lors de la mise à jour de l\'opération: $e');
      // Propager l'exception pour qu'elle soit gérée par l'interface
      rethrow;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Supprimer une opération inactive via l'API
  Future<bool> deleteOperationViaApi(int id) async {
    _isLoading = true;
    notifyListeners();

    try {
      debugPrint('🗑️ Suppression opération inactive $id');

      // Appeler l'API pour supprimer l'opération inactive
      final response = await ApiService.instance.delete('/operations/$id');

      // Vérifier si la requête a été mise en queue (mode offline)
      if (response.data != null && response.data['queued'] == true) {
        // Mode offline : Supprimer localement immédiatement
        await deleteOperation(id);
        debugPrint('⏳ Suppression de l\'opération $id mise en attente (mode hors ligne)');
        return true;
      }

      if (response.statusCode == 200 || response.statusCode == 204) {
        debugPrint('✅ Suppression réussie - Traitement de la réponse');

        // Traiter la réponse qui contient les 3 dernières opérations
        if (response.data != null && response.data['operations'] != null) {
          // Vider la box des opérations
          await _operationBox.clear();

          // Recharger les opérations depuis la réponse API
          await processOperationsFromApi(response.data['operations']);
          debugPrint('✅ Opérations rechargées après suppression');
        } else {
          // Fallback : supprimer localement seulement
          await deleteOperation(id);
        }

        return true;
      }

      debugPrint('❌ Échec suppression - Code: ${response.statusCode}');
      return false;
    } catch (e) {
      debugPrint('❌ Erreur lors de la suppression de l\'opération: $e');
      rethrow;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Supprimer une opération active via l'API (avec réactivation automatique)
  Future<bool> deleteActiveOperationViaApi(int id) async {
    _isLoading = true;
    notifyListeners();

    try {
      debugPrint('🗑️ Suppression opération active $id');

      // Appeler l'API pour supprimer l'opération active
      final response = await ApiService.instance.delete('/operations/$id');

      // Vérifier si la requête a été mise en queue (mode offline)
      if (response.data != null && response.data['queued'] == true) {
        // Mode offline : Supprimer localement et vider les données liées
        await _clearAllRelatedBoxes();
        await deleteOperation(id);
        debugPrint('⏳ Suppression de l\'opération active $id mise en attente (mode hors ligne)');
        return true;
      }

      if (response.statusCode == 200 || response.statusCode == 204) {
        debugPrint(
            '✅ Suppression opération active réussie - Traitement complet');

        // Traiter la réponse complète qui contient tous les groupes de données
        if (response.data != null) {
          await _processActiveDeleteResponse(response.data);
          debugPrint('✅ Données rechargées après suppression opération active');
        } else {
          // Fallback : supprimer localement seulement
          await deleteOperation(id);
        }

        return true;
      }

      debugPrint(
          '❌ Échec suppression opération active - Code: ${response.statusCode}');
      return false;
    } catch (e) {
      debugPrint('❌ Erreur lors de la suppression de l\'opération active: $e');
      rethrow;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Traiter la réponse complète après suppression d'opération active
  Future<void> _processActiveDeleteResponse(
      Map<String, dynamic> responseData) async {
    try {
      debugPrint(
          '🔄 Traitement de la réponse de suppression d\'opération active');

      // Vider toutes les Box concernées
      await _clearAllRelatedBoxes();

      // Traiter les opérations (groupe operations)
      if (responseData['operations'] != null) {
        await processOperationsFromApi(responseData['operations']);
        debugPrint('✅ Opérations traitées');
      }

      // Traiter les secteurs (groupe sectors) via DataLoadingService
      if (responseData['sectors'] != null) {
        await DataLoadingService.instance
            .processSectorsFromApi(responseData['sectors']);
        debugPrint('✅ Secteurs traités');
      }

      // Traiter les passages (groupe passages) via DataLoadingService
      if (responseData['passages'] != null) {
        await DataLoadingService.instance
            .processPassagesFromApi(responseData['passages']);
        debugPrint('✅ Passages traités');
      }

      // Traiter les users_sectors (groupe users_sectors) via DataLoadingService
      if (responseData['users_sectors'] != null) {
        await DataLoadingService.instance
            .processUserSectorsFromApi(responseData['users_sectors']);
        debugPrint('✅ Users_sectors traités');
      }

      debugPrint(
          '🎉 Tous les groupes de données ont été traités après suppression opération active');
    } catch (e) {
      debugPrint(
          '❌ Erreur lors du traitement de la réponse de suppression: $e');
      // Ne pas faire échouer la suppression si le traitement des données supplémentaires échoue
    }
  }

  // Vider toutes les Box liées lors de suppression d'opération active
  Future<void> _clearAllRelatedBoxes() async {
    try {
      // Vider les Box respectives avant rechargement complet
      await _operationBox.clear();

      if (Hive.isBoxOpen(AppKeys.sectorsBoxName)) {
        final sectorsBox = Hive.box<SectorModel>(AppKeys.sectorsBoxName);
        await sectorsBox.clear();
      }

      if (Hive.isBoxOpen(AppKeys.passagesBoxName)) {
        final passagesBox = Hive.box<PassageModel>(AppKeys.passagesBoxName);
        await passagesBox.clear();
      }

      if (Hive.isBoxOpen(AppKeys.userSectorBoxName)) {
        final userSectorsBox =
            Hive.box<UserSectorModel>(AppKeys.userSectorBoxName);
        await userSectorsBox.clear();
      }

      debugPrint('✅ Toutes les Box ont été vidées');
    } catch (e) {
      debugPrint('❌ Erreur lors du vidage des Box: $e');
    }
  }

  // Export Excel d'une opération
  Future<void> exportOperationToExcel(
      int operationId, String operationName) async {
    try {
      debugPrint('📊 Export Excel opération $operationId: $operationName');

      // Générer le nom de fichier avec la date actuelle
      final now = DateTime.now();
      final dateStr =
          '${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}';
      final fileName =
          'operation_${operationName.replaceAll(' ', '_')}_$dateStr.xlsx';

      // Appeler l'API pour télécharger le fichier Excel
      await ApiService.instance.downloadOperationExcel(operationId, fileName);

      debugPrint('✅ Export Excel terminé pour opération $operationId');
    } catch (e) {
      debugPrint('❌ Erreur lors de l\'export Excel: $e');
      rethrow;
    }
  }
}
