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/services/current_user_service.dart';
import 'package:geosector_app/core/constants/app_keys.dart';

class PassageRepository extends ChangeNotifier {
  // Constructeur sans paramètres - utilise ApiService.instance
  PassageRepository();

// Cache pour les statistiques
  Map<String, dynamic>? _cachedStats;

  // Cache de la box pour éviter les vérifications répétées
  Box<PassageModel>? _cachedPassageBox;
  
  // Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
  Box<PassageModel> get _passageBox {
    if (_cachedPassageBox == null) {
      if (!Hive.isBoxOpen(AppKeys.passagesBoxName)) {
        throw Exception('La boîte ${AppKeys.passagesBoxName} n\'est pas ouverte. Initialisez d\'abord l\'application.');
      }
      _cachedPassageBox = Hive.box<PassageModel>(AppKeys.passagesBoxName);
      debugPrint('PassageRepository: Box ${AppKeys.passagesBoxName} mise en cache');
    }
    return _cachedPassageBox!;
  }

  // Méthode publique pour réinitialiser le cache (ex: après nettoyage complet)
  void resetCache() {
    _cachedPassageBox = null;
    debugPrint('🔄 Cache PassageRepository réinitialisé');
  }

// Méthode pour exposer la Box Hive (nécessaire pour ValueListenableBuilder)
  Box<PassageModel> getPassagesBox() {
    try {
      if (!Hive.isBoxOpen(AppKeys.passagesBoxName)) {
        throw Exception('La boîte passages n\'est pas ouverte');
      }
      return Hive.box<PassageModel>(AppKeys.passagesBoxName);
    } catch (e) {
      debugPrint('Erreur lors de l\'accès à la boîte passages: $e');
      rethrow;
    }
  }

  // Stream pour notifier des changements de passages
  StreamController<List<PassageModel>>? _passageStreamController;

  // Getter pour le stream des passages
  Stream<List<PassageModel>> get passageStream {
    _passageStreamController ??= StreamController<List<PassageModel>>.broadcast();
    return _passageStreamController!.stream;
  }

  @override
  void dispose() {
    _passageStreamController?.close();
    super.dispose();
  }

  // ID du secteur par défaut
  int defaultSectorId = 1;
  bool _isLoading = false;

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


  // Récupérer tous les passages
  List<PassageModel> getAllPassages() {
    return _passageBox.values.toList();
  }

  // Récupérer un passage par son ID
  PassageModel? getPassageById(int id) {
    return _passageBox.get(id);
  }

  // Récupérer les passages par secteur
  List<PassageModel> getPassagesBySectorId(int sectorId) {
    return _passageBox.values.where((passage) => passage.fkSector == sectorId).toList();
  }
  
  // Récupérer les passages orphelins (sans secteur)
  List<PassageModel> getOrphanPassages() {
    return _passageBox.values.where((passage) => passage.fkSector == null).toList();
  }

  // Récupérer les passages par type
  List<PassageModel> getPassagesByType(int type) {
    return _passageBox.values.where((passage) => passage.fkType == type).toList();
  }

  // Récupérer les passages par opération
  List<PassageModel> getPassagesByOperation(int operationId) {
    return _passageBox.values.where((passage) => passage.fkOperation == operationId).toList();
  }

// Récupérer les passages par utilisateur (ope_users.id)
  List<PassageModel> getPassagesByUser(int opeUserId) {
    try {
      return _passageBox.values.where((passage) => passage.fkUser == opeUserId).toList();
    } catch (e) {
      debugPrint('Erreur lors de la récupération des passages par utilisateur: $e');
      return [];
    }
  }

  // Récupérer les passages par date
  List<PassageModel> getPassagesByDate(DateTime date) {
    return _passageBox.values.where((passage) {
      // Ignorer les passages sans date
      if (passage.passedAt == null) return false;
      
      final passageDate = DateTime(
        passage.passedAt!.year,
        passage.passedAt!.month,
        passage.passedAt!.day,
      );
      final searchDate = DateTime(date.year, date.month, date.day);
      return passageDate.isAtSameMomentAs(searchDate);
    }).toList();
  }

  // Sauvegarder un passage
  Future<void> savePassage(PassageModel passage) async {
    await _passageBox.put(passage.id, passage);
    resetCache(); // Réinitialiser le cache après modification
    notifyListeners();
    _notifyPassageStream();
  }

  // Sauvegarder plusieurs passages
  Future<void> savePassages(List<PassageModel> passages) async {
    if (passages.isEmpty) return;
    
    // Créer une map avec l'ID comme clé pour putAll
    final Map<dynamic, PassageModel> passagesMap = {
      for (final passage in passages) passage.id: passage
    };
    
    // Sauvegarder tous les passages en une seule opération
    await _passageBox.putAll(passagesMap);
    
    resetCache(); // Réinitialiser le cache après modification massive
    notifyListeners();
    _notifyPassageStream();
  }

  // Supprimer un passage
  Future<void> deletePassage(int id) async {
    await _passageBox.delete(id);
    resetCache(); // Réinitialiser le cache après suppression
    notifyListeners();
    _notifyPassageStream();
  }

  // Notifier le stream des changements
  void _notifyPassageStream() {
    _passageStreamController?.add(getAllPassages());
  }

  // Créer un passage via l'API et retourner le passage créé
  Future<PassageModel?> createPassageWithReturn(PassageModel passage, {BuildContext? context}) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Préparer les données pour l'API
      final data = passage.toJson();

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

      // Vérifier si la requête a été mise en file d'attente (mode offline)
      if (response.data['queued'] == true) {
        // Mode offline : créer localement avec un ID temporaire
        final offlinePassage = passage.copyWith(
          id: DateTime.now().millisecondsSinceEpoch, // ID temporaire unique
          lastSyncedAt: null,
          isSynced: false,
        );

        await savePassage(offlinePassage);

        // Afficher le dialog d'information si un contexte est fourni
        if (context != null && context.mounted) {
          showDialog(
            context: context,
            builder: (dialogContext) => AlertDialog(
              title: const Row(
                children: [
                  Icon(Icons.cloud_queue, color: Colors.orange),
                  SizedBox(width: 12),
                  Text('Mode hors ligne'),
                ],
              ),
              content: Column(
                mainAxisSize: MainAxisSize.min,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text('Votre passage a été enregistré localement.'),
                  const SizedBox(height: 16),
                  Container(
                    padding: const EdgeInsets.all(12),
                    decoration: BoxDecoration(
                      color: Colors.orange.shade50,
                      borderRadius: BorderRadius.circular(8),
                      border: Border.all(color: Colors.orange.shade200),
                    ),
                    child: const Row(
                      children: [
                        Icon(Icons.info_outline, size: 16, color: Colors.orange),
                        SizedBox(width: 8),
                        Expanded(
                          child: Text(
                            'Le passage apparaîtra dans votre liste après synchronisation.',
                            style: TextStyle(fontSize: 13),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
              actions: [
                ElevatedButton(
                  onPressed: () => Navigator.of(dialogContext).pop(),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.orange,
                  ),
                  child: const Text('Compris'),
                ),
              ],
            ),
          );
        }

        return offlinePassage; // Retourner le passage créé localement
      }

      // Mode online : traitement normal
      if (response.statusCode == 201 || response.statusCode == 200) {
        // Récupérer l'ID du nouveau passage depuis la réponse (passage_id ou id)
        final rawId = response.data['passage_id'] ?? response.data['id'];
        final passageId = rawId is String ? int.parse(rawId) : rawId as int;

        // Créer le passage localement avec l'ID retourné par l'API
        final newPassage = passage.copyWith(
          id: passageId,
          lastSyncedAt: DateTime.now(),
          isSynced: true,
        );

        await savePassage(newPassage);
        return newPassage; // Retourner le passage créé avec son ID réel
      }
      return null;
    } catch (e) {
      debugPrint('Erreur lors de la création du passage: $e');
      return null;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Créer un passage via l'API (ancienne méthode pour compatibilité)
  Future<bool> createPassage(PassageModel passage, {BuildContext? context}) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Préparer les données pour l'API
      final data = passage.toJson();

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

      // Vérifier si la requête a été mise en file d'attente
      if (response.data['queued'] == true) {
        // Mode offline : NE PAS créer le passage dans Hive
        // Il sera créé automatiquement après synchronisation
        
        // Afficher un message explicatif
        if (context != null && context.mounted) {
          showDialog(
            context: context,
            barrierDismissible: false,
            builder: (dialogContext) => AlertDialog(
              icon: const Icon(Icons.cloud_queue, color: Colors.orange, size: 48),
              title: const Text('Création en attente'),
              content: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  const Text(
                    'Votre passage a été enregistré et sera créé dès que la connexion sera rétablie.',
                    style: TextStyle(fontSize: 14),
                  ),
                  const SizedBox(height: 16),
                  Container(
                    padding: const EdgeInsets.all(12),
                    decoration: BoxDecoration(
                      color: Colors.orange.shade50,
                      borderRadius: BorderRadius.circular(8),
                      border: Border.all(color: Colors.orange.shade200),
                    ),
                    child: const Row(
                      children: [
                        Icon(Icons.info_outline, size: 16, color: Colors.orange),
                        SizedBox(width: 8),
                        Expanded(
                          child: Text(
                            'Le passage apparaîtra dans votre liste après synchronisation.',
                            style: TextStyle(fontSize: 13),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
              actions: [
                ElevatedButton(
                  onPressed: () => Navigator.of(dialogContext).pop(),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.orange,
                  ),
                  child: const Text('Compris'),
                ),
              ],
            ),
          );
        }
        
        // Retourner true car la requête est bien en file d'attente
        return true;
      }
      
      // Mode online : traitement normal
      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 passage localement avec l'ID retourné par l'API
        final newPassage = passage.copyWith(
          id: passageId,
          lastSyncedAt: DateTime.now(),
          isSynced: true,
        );

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

  // Mettre à jour un passage via l'API
  Future<bool> updatePassage(PassageModel passage, {BuildContext? context}) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Préparer les données pour l'API
      final data = passage.toJson();

      // Appeler l'API pour mettre à jour le passage
      final response = await ApiService.instance.put('/passages/${passage.id}', data: data);
      
      // Vérifier si la requête a été mise en file d'attente
      if (response.data['queued'] == true) {
        // Récupérer l'utilisateur actuel (ope_users.id)
        final currentOpeUserId = CurrentUserService.instance.opeUserId;

        // Mode offline : mettre à jour localement et marquer comme non synchronisé
        final offlinePassage = passage.copyWith(
          fkUser: currentOpeUserId, // Le passage appartient à l'utilisateur qui l'a modifié (ope_users.id)
          lastSyncedAt: null,
          isSynced: false,
        );

        await savePassage(offlinePassage);
        
        // Afficher un message si un contexte est fourni
        if (context != null && context.mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Row(
                children: [
                  Icon(Icons.cloud_queue, color: Colors.white),
                  SizedBox(width: 12),
                  Expanded(
                    child: Text(
                      'Modification en attente de synchronisation',
                    ),
                  ),
                ],
              ),
              backgroundColor: Colors.orange,
              duration: Duration(seconds: 3),
            ),
          );
        }
        
        return true;
      }
      
      // Mode online : traitement normal
      if (response.statusCode == 200) {
        // Récupérer l'utilisateur actuel (ope_users.id)
        final currentOpeUserId = CurrentUserService.instance.opeUserId;

        // Mettre à jour le passage localement avec le user actuel
        final updatedPassage = passage.copyWith(
          fkUser: currentOpeUserId, // Le passage appartient à l'utilisateur qui l'a modifié (ope_users.id)
          lastSyncedAt: DateTime.now(),
          isSynced: true,
        );
        await savePassage(updatedPassage);
        return true;
      }

      throw Exception('Mise à jour refusée par le serveur');
    } catch (e) {
      debugPrint('Erreur lors de la mise à jour du passage: $e');
      rethrow; // Propager l'exception originale avec son message
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Supprimer un passage via l'API
  Future<bool> deletePassageViaApi(int id, {BuildContext? context}) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Appeler l'API pour supprimer le passage
      final response = await ApiService.instance.delete('/passages/$id');

      if (response.statusCode == 200 || response.statusCode == 204 || response.data['queued'] == true) {
        // Supprimer le passage localement
        await deletePassage(id);
        
        // Si mis en file d'attente, informer l'utilisateur
        if (response.data['queued'] == true && context != null && context.mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Row(
                children: [
                  Icon(Icons.cloud_queue, color: Colors.white),
                  SizedBox(width: 12),
                  Expanded(
                    child: Text(
                      'Suppression en attente de synchronisation',
                    ),
                  ),
                ],
              ),
              backgroundColor: Colors.orange,
              duration: Duration(seconds: 3),
            ),
          );
        }
        
        return true;
      }

      return false;
    } catch (e) {
      debugPrint('Erreur lors de la suppression du passage: $e');
      return false;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Traitement des données de passages depuis l'API
  Future<void> processPassagesData(dynamic passagesData) async {
    try {
      debugPrint('Traitement des données des passages...');

      // Vérifier que les données sont au bon format
      if (passagesData == null) {
        debugPrint('Aucune donnée de passage à traiter');
        return;
      }

      List<dynamic> passagesList;
      if (passagesData is List) {
        passagesList = passagesData;
      } else if (passagesData is Map && passagesData.containsKey('data')) {
        passagesList = passagesData['data'] as List<dynamic>;
      } else {
        debugPrint('Format de données de passages non reconnu');
        return;
      }

      // Vider la boîte avant d'ajouter les nouvelles données
      await _passageBox.clear();

      // Traiter chaque passage
      int count = 0;
      for (final passageData in passagesList) {
        try {
          final passage = PassageModel.fromJson(passageData);
          await _passageBox.put(passage.id, passage);
          count++;
        } catch (e) {
          debugPrint('Erreur lors du traitement d\'un passage: $e');
        }
      }

      debugPrint('$count passages traités et stockés');
      resetCache(); // Réinitialiser le cache après traitement des données API
      notifyListeners();
      _notifyPassageStream();
    } catch (e) {
      debugPrint('Erreur lors du traitement des passages: $e');
    }
  }

  // Synchroniser tous les passages non synchronisés
  Future<void> syncUnsyncedPassages() async {
    final unsyncedPassages = _passageBox.values.where((passage) => !passage.isSynced).toList();

    for (final passage in unsyncedPassages) {
      try {
        await updatePassage(passage);
      } catch (e) {
        debugPrint('Erreur lors de la synchronisation du passage ${passage.id}: $e');
      }
    }
  }

  // Recalculer les statistiques (appelée par le ValueListenableBuilder)
  Map<String, dynamic> calculatePassageStatistics() {
    final allPassages = getAllPassages();

    debugPrint('📊 Calcul des statistiques: ${allPassages.length} passages');

    // Statistiques globales
    final globalStats = {
      'total': allPassages.length,
      'effectues': allPassages.where((p) => p.fkType == 1).length,
      'a_finaliser': allPassages.where((p) => p.fkType == 2).length,
      'refuses': allPassages.where((p) => p.fkType == 3).length,
      'dons': allPassages.where((p) => p.fkType == 4).length,
      'lots': allPassages.where((p) => p.fkType == 5).length,
      'maisons_vides': allPassages.where((p) => p.fkType == 6).length,
    };

    // Statistiques par utilisateur
    final Map<int, Map<String, int>> statsByUser = {};

    // Grouper les passages par utilisateur
    final passagesByUser = <int, List<PassageModel>>{};
    for (final passage in allPassages) {
      passagesByUser.putIfAbsent(passage.fkUser, () => []).add(passage);
    }

    // Calculer les statistiques pour chaque utilisateur
    for (final entry in passagesByUser.entries) {
      final opeUserId = entry.key; // ID de l'utilisateur dans ope_users
      final userPassages = entry.value;

      statsByUser[opeUserId] = {
        'total': userPassages.length,
        'effectues': userPassages.where((p) => p.fkType == 1).length,
        'a_finaliser': userPassages.where((p) => p.fkType == 2).length,
        'refuses': userPassages.where((p) => p.fkType == 3).length,
        'dons': userPassages.where((p) => p.fkType == 4).length,
        'lots': userPassages.where((p) => p.fkType == 5).length,
        'maisons_vides': userPassages.where((p) => p.fkType == 6).length,
      };
    }

    // Statistiques par type
    final statsByType = {
      1: allPassages.where((p) => p.fkType == 1).length,
      2: allPassages.where((p) => p.fkType == 2).length,
      3: allPassages.where((p) => p.fkType == 3).length,
      4: allPassages.where((p) => p.fkType == 4).length,
      5: allPassages.where((p) => p.fkType == 5).length,
      6: allPassages.where((p) => p.fkType == 6).length,
    };

    // Mettre en cache et retourner
    _cachedStats = {
      'global': globalStats,
      'by_user': statsByUser,
      'by_type': statsByType,
      'user_count': statsByUser.length,
      'calculated_at': DateTime.now().toIso8601String(),
    };

    return _cachedStats!;
  }

  // Getter simple pour les statistiques (optionnel, pour usage sans ValueListenableBuilder)
  Map<String, dynamic> getPassageStatistics() {
    return _cachedStats ?? calculatePassageStatistics();
  }

  // Vider tous les passages
  Future<void> clearAllPassages() async {
    await _passageBox.clear();
    resetCache(); // Réinitialiser le cache après suppression de toutes les données
    notifyListeners();
    _notifyPassageStream();
  }
}
