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

class PassageRepository 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<PassageModel>? _box;

  Box<PassageModel> get _passageBox {
    if (_box != null && _box!.isOpen) {
      return _box!;
    }

    if (!Hive.isBoxOpen(AppKeys.passagesBoxName)) {
      throw StateError(
          'La boîte ${AppKeys.passagesBoxName} n\'est pas ouverte. Appelez _ensureBoxIsOpen() avant d\'accéder à la boîte.');
    }

    _box = Hive.box<PassageModel>(AppKeys.passagesBoxName);
    return _box!;
  }

  // Méthode pour vérifier si la boîte est ouverte et l'ouvrir si nécessaire
  Future<void> _ensureBoxIsOpen() async {
    final boxName = AppKeys.passagesBoxName;

    // Si nous avons déjà une référence à la boîte et qu'elle est ouverte, retourner
    if (_box != null && _box!.isOpen) {
      return;
    }

    // Si la boîte est déjà ouverte, récupérer la référence
    if (Hive.isBoxOpen(boxName)) {
      _box = Hive.box<PassageModel>(boxName);
      debugPrint(
          'PassageRepository: Boîte $boxName déjà ouverte, référence récupérée');
      return;
    }

    // Sinon, ouvrir la boîte
    try {
      debugPrint('PassageRepository: Ouverture de la boîte $boxName...');
      _box = await Hive.openBox<PassageModel>(boxName);
      debugPrint('PassageRepository: Boîte $boxName ouverte avec succès');
    } catch (e) {
      debugPrint(
          'PassageRepository: ERREUR lors de l\'ouverture de la boîte $boxName: $e');
      rethrow; // Propager l'erreur pour permettre une gestion appropriée
    }
  }

  final ApiService _apiService;

  bool _isLoading = false;

  PassageRepository(this._apiService);

  // Getters
  bool get isLoading => _isLoading;
  List<PassageModel> get passages => getAllPassages();

  // Récupérer tous les passages
  List<PassageModel> getAllPassages() {
    try {
      // S'assurer que la boîte est ouverte avant d'y accéder
      _ensureBoxIsOpen().then((_) {
        debugPrint(
            'PassageRepository: Boîte ouverte avec succès pour getAllPassages');
      }).catchError((e) {
        debugPrint(
            'PassageRepository: Erreur lors de l\'ouverture de la boîte pour getAllPassages: $e');
      });

      return _passageBox.values.toList();
    } catch (e) {
      debugPrint('PassageRepository: Erreur dans getAllPassages: $e');
      return []; // Retourner une liste vide en cas d'erreur
    }
  }

  // Récupérer un passage par son ID
  PassageModel? getPassageById(int id) {
    try {
      // S'assurer que la boîte est ouverte avant d'y accéder
      _ensureBoxIsOpen().then((_) {
        debugPrint(
            'PassageRepository: Boîte ouverte avec succès pour getPassageById');
      }).catchError((e) {
        debugPrint(
            'PassageRepository: Erreur lors de l\'ouverture de la boîte pour getPassageById: $e');
      });

      return _passageBox.get(id);
    } catch (e) {
      debugPrint('PassageRepository: Erreur dans getPassageById: $e');
      return null;
    }
  }

  // Récupérer les passages par secteur
  List<PassageModel> getPassagesBySector(int sectorId) {
    try {
      // S'assurer que la boîte est ouverte avant d'y accéder
      _ensureBoxIsOpen().then((_) {
        debugPrint(
            'PassageRepository: Boîte ouverte avec succès pour getPassagesBySector');
      }).catchError((e) {
        debugPrint(
            'PassageRepository: Erreur lors de l\'ouverture de la boîte pour getPassagesBySector: $e');
      });

      return _passageBox.values
          .where((passage) => passage.fkSector == sectorId)
          .toList();
    } catch (e) {
      debugPrint('PassageRepository: Erreur dans getPassagesBySector: $e');
      return [];
    }
  }

  // Récupérer les passages par opération
  List<PassageModel> getPassagesByOperation(int operationId) {
    try {
      // S'assurer que la boîte est ouverte avant d'y accéder
      _ensureBoxIsOpen().then((_) {
        debugPrint(
            'PassageRepository: Boîte ouverte avec succès pour getPassagesByOperation');
      }).catchError((e) {
        debugPrint(
            'PassageRepository: Erreur lors de l\'ouverture de la boîte pour getPassagesByOperation: $e');
      });

      return _passageBox.values
          .where((passage) => passage.fkOperation == operationId)
          .toList();
    } catch (e) {
      debugPrint('PassageRepository: Erreur dans getPassagesByOperation: $e');
      return [];
    }
  }

  // Récupérer les passages par type
  List<PassageModel> getPassagesByType(int typeId) {
    try {
      // S'assurer que la boîte est ouverte avant d'y accéder
      _ensureBoxIsOpen().then((_) {
        debugPrint(
            'PassageRepository: Boîte ouverte avec succès pour getPassagesByType');
      }).catchError((e) {
        debugPrint(
            'PassageRepository: Erreur lors de l\'ouverture de la boîte pour getPassagesByType: $e');
      });

      return _passageBox.values
          .where((passage) => passage.fkType == typeId)
          .toList();
    } catch (e) {
      debugPrint('PassageRepository: Erreur dans getPassagesByType: $e');
      return [];
    }
  }

  // Récupérer les passages par type de règlement
  List<PassageModel> getPassagesByPaymentType(int paymentTypeId) {
    try {
      // S'assurer que la boîte est ouverte avant d'y accéder
      _ensureBoxIsOpen().then((_) {
        debugPrint(
            'PassageRepository: Boîte ouverte avec succès pour getPassagesByPaymentType');
      }).catchError((e) {
        debugPrint(
            'PassageRepository: Erreur lors de l\'ouverture de la boîte pour getPassagesByPaymentType: $e');
      });

      return _passageBox.values
          .where((passage) => passage.fkTypeReglement == paymentTypeId)
          .toList();
    } catch (e) {
      debugPrint('PassageRepository: Erreur dans getPassagesByPaymentType: $e');
      return [];
    }
  }

  // Sauvegarder un passage
  Future<void> savePassage(PassageModel passage) async {
    await _passageBox.put(passage.id, passage);
    notifyListeners();
  }

  // Supprimer un passage
  Future<void> deletePassage(int id) async {
    await _passageBox.delete(id);
    notifyListeners();
  }

  // Traiter les passages reçus de l'API
  Future<void> processPassagesFromApi(List<dynamic> passagesData) async {
    _isLoading = true;
    notifyListeners();

    try {
      for (var passageData in passagesData) {
        final passageJson = passageData as Map<String, dynamic>;
        final passageId = passageJson['id'] is String
            ? int.parse(passageJson['id'])
            : passageJson['id'] as int;

        // Vérifier si le passage existe déjà
        PassageModel? existingPassage = getPassageById(passageId);

        if (existingPassage == null) {
          // Créer un nouveau passage
          final newPassage = PassageModel.fromJson(passageJson);
          await savePassage(newPassage);
        } else {
          // Mettre à jour le passage existant avec les nouvelles données
          final updatedPassage = PassageModel.fromJson(passageJson).copyWith(
            lastSyncedAt: DateTime.now(),
            isActive: existingPassage.isActive,
            isSynced: true,
          );
          await savePassage(updatedPassage);
        }
      }
    } catch (e) {
      debugPrint('Erreur lors du traitement des passages: $e');
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Créer un nouveau passage
  Future<bool> createPassage({
    required int fkOperation,
    required int fkSector,
    required int fkUser,
    required int fkType,
    required String fkAdresse,
    required DateTime passedAt,
    required String numero,
    required String rue,
    String rueBis = '',
    required String ville,
    String residence = '',
    required int fkHabitat,
    String appt = '',
    String niveau = '',
    required String gpsLat,
    required String gpsLng,
    String nomRecu = '',
    String remarque = '',
    required String montant,
    required int fkTypeReglement,
    String name = '',
    String email = '',
    String phone = '',
  }) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Préparer les données pour l'API
      final Map<String, dynamic> data = {
        'fk_operation': fkOperation,
        'fk_sector': fkSector,
        'fk_user': fkUser,
        'fk_type': fkType,
        'fk_adresse': fkAdresse,
        'passed_at': passedAt.toIso8601String(),
        'numero': numero,
        'rue': rue,
        'rue_bis': rueBis,
        'ville': ville,
        'residence': residence,
        'fk_habitat': fkHabitat,
        'appt': appt,
        'niveau': niveau,
        'gps_lat': gpsLat,
        'gps_lng': gpsLng,
        'nom_recu': nomRecu,
        'remarque': remarque,
        'montant': montant,
        'fk_type_reglement': fkTypeReglement,
        'name': name,
        'email': email,
        'phone': phone,
      };

      // Appeler l'API pour créer le passage
      final response = await _apiService.post('/passages', data: data);

      if (response.statusCode == 201 || response.statusCode == 200) {
        // Récupérer l'ID du nouveau passage
        final passageId = response.data['id'] is String
            ? int.parse(response.data['id'])
            : response.data['id'] as int;

        // Créer le modèle local
        final newPassage = PassageModel(
          id: passageId,
          fkOperation: fkOperation,
          fkSector: fkSector,
          fkUser: fkUser,
          fkType: fkType,
          fkAdresse: fkAdresse,
          passedAt: passedAt,
          numero: numero,
          rue: rue,
          rueBis: rueBis,
          ville: ville,
          residence: residence,
          fkHabitat: fkHabitat,
          appt: appt,
          niveau: niveau,
          gpsLat: gpsLat,
          gpsLng: gpsLng,
          nomRecu: nomRecu,
          remarque: remarque,
          montant: montant,
          fkTypeReglement: fkTypeReglement,
          nbPassages: 1, // Par défaut pour un nouveau passage
          name: name,
          email: email,
          phone: phone,
          lastSyncedAt: DateTime.now(),
          isActive: true,
          isSynced: true,
        );

        await savePassage(newPassage);
        return true;
      } else {
        debugPrint(
            'Erreur lors de la création du passage: ${response.statusMessage}');
        return false;
      }
    } catch (e) {
      debugPrint('Erreur lors de la création du passage: $e');
      return false;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Mettre à jour un passage existant
  Future<bool> updatePassage(PassageModel passage) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Préparer les données pour l'API
      final Map<String, dynamic> data = passage.toJson();

      // Appeler l'API pour mettre à jour le passage
      final response =
          await _apiService.put('/passages/${passage.id}', data: data);

      if (response.statusCode == 200) {
        // Mettre à jour le modèle local
        final updatedPassage = passage.copyWith(
          lastSyncedAt: DateTime.now(),
          isSynced: true,
        );

        await savePassage(updatedPassage);
        return true;
      } else {
        debugPrint(
            'Erreur lors de la mise à jour du passage: ${response.statusMessage}');

        // Marquer comme non synchronisé mais sauvegarder localement
        final updatedPassage = passage.copyWith(
          lastSyncedAt: DateTime.now(),
          isSynced: false,
        );

        await savePassage(updatedPassage);
        return false;
      }
    } catch (e) {
      debugPrint('Erreur lors de la mise à jour du passage: $e');

      // Marquer comme non synchronisé mais sauvegarder localement
      final updatedPassage = passage.copyWith(
        lastSyncedAt: DateTime.now(),
        isSynced: false,
      );

      await savePassage(updatedPassage);
      return false;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Synchroniser tous les passages non synchronisés
  Future<void> syncUnsyncedPassages() async {
    try {
      final hasConnection = await _apiService.hasInternetConnection();

      if (!hasConnection) {
        return;
      }

      final unsyncedPassages =
          _passageBox.values.where((passage) => !passage.isSynced).toList();

      if (unsyncedPassages.isEmpty) {
        return;
      }

      _isLoading = true;
      notifyListeners();

      for (final passage in unsyncedPassages) {
        try {
          if (passage.id < 0) {
            // Nouveau passage créé localement, à envoyer à l'API
            await createPassage(
              fkOperation: passage.fkOperation,
              fkSector: passage.fkSector,
              fkUser: passage.fkUser,
              fkType: passage.fkType,
              fkAdresse: passage.fkAdresse,
              passedAt: passage.passedAt,
              numero: passage.numero,
              rue: passage.rue,
              rueBis: passage.rueBis,
              ville: passage.ville,
              residence: passage.residence,
              fkHabitat: passage.fkHabitat,
              appt: passage.appt,
              niveau: passage.niveau,
              gpsLat: passage.gpsLat,
              gpsLng: passage.gpsLng,
              nomRecu: passage.nomRecu,
              remarque: passage.remarque,
              montant: passage.montant,
              fkTypeReglement: passage.fkTypeReglement,
              name: passage.name,
              email: passage.email,
              phone: passage.phone,
            );

            // Supprimer l'ancien passage avec ID temporaire
            await deletePassage(passage.id);
          } else {
            // Passage existant à mettre à jour
            await updatePassage(passage);
          }
        } catch (e) {
          debugPrint(
              'Erreur lors de la synchronisation du passage ${passage.id}: $e');
        }
      }
    } catch (e) {
      debugPrint('Erreur lors de la synchronisation des passages: $e');
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Récupérer les passages depuis l'API
  Future<void> fetchPassages() async {
    try {
      final hasConnection = await _apiService.hasInternetConnection();

      if (!hasConnection) {
        return;
      }

      _isLoading = true;
      notifyListeners();

      final response = await _apiService.get('/passages');

      if (response.statusCode == 200) {
        final List<dynamic> passagesData = response.data;
        await processPassagesFromApi(passagesData);
      }
    } catch (e) {
      debugPrint('Erreur lors de la récupération des passages: $e');
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Vider tous les passages
  Future<void> clearAllPassages() async {
    await _passageBox.clear();
    notifyListeners();
  }
}
