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

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

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

  bool _isLoading = false;

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

  // Getters
  bool get isLoading => _isLoading;
  List<MembreModel> get membres => getAllMembres();

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


  // === MÉTHODES SPÉCIFIQUES AUX MEMBRES ===

  // Récupérer les membres par amicale
  List<MembreModel> getMembresByAmicale(int fkEntite) {
    try {
      return _membreBox.values.where((membre) => membre.fkEntite == fkEntite).toList();
    } catch (e) {
      debugPrint('Erreur lors de la récupération des membres par amicale: $e');
      return [];
    }
  }

  // Récupérer les membres actifs par amicale
  List<MembreModel> getActiveMembresByAmicale(int fkEntite) {
    try {
      return _membreBox.values.where((membre) => membre.fkEntite == fkEntite && membre.isActive == true).toList();
    } catch (e) {
      debugPrint('Erreur lors de la récupération des membres actifs par amicale: $e');
      return [];
    }
  }

  // Compter les membres par amicale
  int countMembresByAmicale(int fkEntite) {
    try {
      return _membreBox.values.where((membre) => membre.fkEntite == fkEntite).length;
    } catch (e) {
      debugPrint('Erreur lors du comptage des membres par amicale: $e');
      return 0;
    }
  }

  // === MÉTHODES CRUD DE BASE ===

  // Récupérer tous les membres
  List<MembreModel> getAllMembres() {
    try {
      return _membreBox.values.toList();
    } catch (e) {
      debugPrint('Erreur lors de la récupération des membres: $e');
      return [];
    }
  }

  // Récupérer un membre par son ID
  MembreModel? getMembreById(int id) {
    try {
      return _membreBox.get(id);
    } catch (e) {
      debugPrint('Erreur lors de la récupération du membre: $e');
      return null;
    }
  }

  // Sauvegarder un membre
  Future<void> saveMembreBox(MembreModel membre) async {
    await _membreBox.put(membre.id, membre);
    resetCache(); // Réinitialiser le cache après modification
    notifyListeners();
  }

  // Supprimer un membre
  Future<void> deleteMembreBox(int id) async {
    await _membreBox.delete(id);
    resetCache(); // Réinitialiser le cache après modification
    notifyListeners();
  }

  // === MÉTHODES API ===

  // Créer un membre via l'API
  Future<MembreModel?> createMembre(MembreModel membre, {String? password, BuildContext? context}) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Convertir en UserModel pour l'API
      final userModel = membre.toUserModel();
      final data = userModel.toJson();
      data.remove('id'); // L'API génère l'ID
      data.remove('created_at'); // L'API génère created_at
      // Supprimer les champs de session qui ne doivent pas être envoyés
      data.remove('session_id');
      data.remove('session_expiry');
      data.remove('last_path');
      
      // Convertir is_active en chk_active pour l'API
      if (data.containsKey('is_active')) {
        data['chk_active'] = data['is_active'] ? 1 : 0;
        data.remove('is_active');
      }
      
      // Convertir role en fk_role pour l'API
      if (data.containsKey('role')) {
        data['fk_role'] = data['role'];
        data.remove('role');
      }
      
      // Ajouter le mot de passe si fourni (sera ignoré par l'API si chk_mdp_manuel=0)
      if (password != null && password.isNotEmpty) {
        data['password'] = password;
        debugPrint('🔑 Mot de passe inclus dans la requête');
      } else {
        debugPrint('⚠️ Pas de mot de passe fourni');
      }
      
      // Vérifier la présence de l'username (sera ignoré par l'API si chk_username_manuel=0)
      if (data.containsKey('username') && data['username'] != null && data['username'].toString().isNotEmpty) {
        debugPrint('👤 Username inclus dans la requête: ${data['username']}');
      } else {
        debugPrint('⚠️ Username manquant ou vide dans la requête');
        // Si pas d'username, s'assurer qu'il n'est pas envoyé du tout
        data.remove('username');
      }
      
      LoggerService.api('Données envoyées à l\'API pour création membre: $data');

      // Appeler l'API users
      final response = await ApiService.instance.post('/users', 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 le membre dans Hive
        debugPrint('⏳ Création du membre 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(
                'Le membre sera créé 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 null; // Retourner null car pas de membre créé localement
      }

      // Vérifier d'abord si on a une réponse avec un statut d'erreur
      if (response.data != null && response.data is Map<String, dynamic>) {
        final responseData = response.data as Map<String, dynamic>;
        
        // Si l'API retourne un status error, propager le message
        if (responseData['status'] == 'error' && responseData['message'] != null) {
          throw Exception(responseData['message']);
        }
        
        // Si succès avec code 201
        if (response.statusCode == 201 && responseData['status'] == 'success') {
          debugPrint('🎉 Réponse API création utilisateur: $responseData');

          // L'API retourne {"status":"success","message":"Utilisateur créé avec succès","id":"10027748"}
          final userId = responseData['id'] is String ? int.parse(responseData['id']) : responseData['id'] as int;

          // Créer le nouveau membre avec l'ID retourné par l'API
          final createdMember = MembreModel(
            id: userId,
            fkEntite: membre.fkEntite,
            role: membre.role,
            fkTitre: membre.fkTitre,
            name: membre.name,
            firstName: membre.firstName,
            username: membre.username,
            sectName: membre.sectName,
            email: membre.email,
            phone: membre.phone,
            mobile: membre.mobile,
            dateNaissance: membre.dateNaissance,
            dateEmbauche: membre.dateEmbauche,
            createdAt: DateTime.now(),
            isActive: membre.isActive,
          );

          // Sauvegarder localement dans Hive (saveMembreBox gère déjà _resetCache)
          await saveMembreBox(createdMember);

          debugPrint('✅ Membre créé avec l\'ID: $userId et sauvegardé localement');
          return createdMember;
        }
      }

      LoggerService.error('Échec création membre - Code: ${response.statusCode}');
      throw Exception('Erreur lors de la création du membre');
    } catch (e) {
      // Ne pas logger les détails techniques de DioException
      if (e is ApiException) {
        LoggerService.error('Erreur lors de la création du membre: ${e.message}');
      } else {
        LoggerService.error('Erreur lors de la création du membre');
      }
      rethrow; // Propager l'exception pour la gestion d'erreurs
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Mettre à jour un membre via l'API
  Future<bool> updateMembre(MembreModel membre, {String? password}) async {
    _isLoading = true;
    notifyListeners();

    try {
      // Convertir en UserModel pour l'API
      final userModel = membre.toUserModel();
      final data = userModel.toJson();
      // Supprimer les champs de session qui ne doivent pas être envoyés
      data.remove('session_id');
      data.remove('session_expiry');
      data.remove('last_path');
      
      // Convertir is_active en chk_active pour l'API
      if (data.containsKey('is_active')) {
        data['chk_active'] = data['is_active'] ? 1 : 0;
        data.remove('is_active');
      }
      
      // Convertir role en fk_role pour l'API
      if (data.containsKey('role')) {
        data['fk_role'] = data['role'];
        data.remove('role');
      }
      
      // Ajouter le mot de passe si fourni (sera ignoré par l'API si chk_mdp_manuel=0)
      if (password != null && password.isNotEmpty) {
        data['password'] = password;
        debugPrint('🔑 Mot de passe inclus dans la requête de mise à jour');
      } else {
        debugPrint('⚠️ Pas de mot de passe fourni pour la mise à jour');
      }
      
      // L'username ne devrait pas être modifiable en update, mais on le garde pour l'API
      if (data.containsKey('username') && data['username'] != null && data['username'].toString().isNotEmpty) {
        debugPrint('👤 Username présent dans la requête de mise à jour: ${data['username']}');
      } else {
        debugPrint('⚠️ Username manquant dans la requête de mise à jour');
      }
      
      LoggerService.api('Données envoyées à l\'API pour mise à jour membre: $data');

      // Appeler l'API users au lieu de membres
      final response = await ApiService.instance.put('/users/${membre.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
        await saveMembreBox(membre);
        debugPrint('⏳ Modification du membre ${membre.id} mise en attente (mode hors ligne)');
        return true;
      }

      // Si on arrive ici, c'est que la requête a réussi (200)
      // Sauvegarder le membre mis à jour localement
      await saveMembreBox(membre);
      return true;
      
    } catch (e) {
      // Ne pas logger les détails techniques de DioException
      if (e is ApiException) {
        LoggerService.error('Erreur lors de la mise à jour du membre: ${e.message}');
      } else {
        LoggerService.error('Erreur lors de la mise à jour du membre');
      }
      
      // Si c'est une DioException, elle sera automatiquement convertie en ApiException
      // par ApiException.fromDioException() qui extrait le message de l'API
      rethrow; // Propager l'exception pour que le message d'erreur soit affiché
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Réinitialiser le mot de passe d'un membre via l'API
  Future<bool> resetMemberPassword(int membreId) async {
    _isLoading = true;
    notifyListeners();

    try {
      final response = await ApiService.instance.post('/users/$membreId/reset-password');

      // Vérifier si on a une réponse avec un statut d'erreur
      if (response.data != null && response.data is Map<String, dynamic>) {
        final responseData = response.data as Map<String, dynamic>;
        if (responseData['status'] == 'error' && responseData['message'] != null) {
          throw Exception(responseData['message']);
        }
      }

      if (response.statusCode == 200) {
        return true;
      }

      throw Exception('Erreur lors de la réinitialisation du mot de passe');
    } catch (e) {
      // Ne pas logger les détails techniques de DioException
      if (e is ApiException) {
        LoggerService.error('Erreur lors de la réinitialisation du mot de passe: ${e.message}');
      } else {
        LoggerService.error('Erreur lors de la réinitialisation du mot de passe');
      }
      rethrow;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Supprimer un membre via l'API avec transfert optionnel
  Future<bool> deleteMembre(int membreId, [int? transferToUserId, int? operationId]) async {
    _isLoading = true;
    notifyListeners();

    try {
      String endpoint = '/users/$membreId';

      // Construire les paramètres query SEULEMENT si on a des passages à transférer
      List<String> queryParams = [];

      if (transferToUserId != null && transferToUserId > 0) {
        queryParams.add('transfer_to=$transferToUserId');

        // Ajouter operation_id SEULEMENT s'il y a un transfert
        if (operationId != null && operationId > 0) {
          queryParams.add('operation_id=$operationId');
        }
      }

      // Ajouter les paramètres à l'endpoint
      if (queryParams.isNotEmpty) {
        endpoint += '?${queryParams.join('&')}';
      }

      LoggerService.api('DELETE endpoint: $endpoint');

      final response = await ApiService.instance.delete(endpoint);

      // 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 deleteMembreBox(membreId);
        debugPrint('⏳ Suppression du membre $membreId mise en attente (mode hors ligne)');
        return true;
      }

      // Vérifier si on a une réponse avec un statut d'erreur
      if (response.data != null && response.data is Map<String, dynamic>) {
        final responseData = response.data as Map<String, dynamic>;
        if (responseData['status'] == 'error' && responseData['message'] != null) {
          throw Exception(responseData['message']);
        }
      }

      if (response.statusCode == 200 || response.statusCode == 204) {
        // Supprimer le membre localement
        await deleteMembreBox(membreId);
        return true;
      }

      throw Exception('Erreur lors de la suppression du membre');
    } catch (e) {
      // Ne pas logger les détails techniques de DioException
      if (e is ApiException) {
        LoggerService.error('Erreur lors de la suppression du membre: ${e.message}');
      } else {
        LoggerService.error('Erreur lors de la suppression du membre');
      }
      rethrow;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // === TRAITEMENT DES DONNÉES ===

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

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

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

      // Vider la boîte avant d'ajouter les nouvelles données
      await _membreBox.clear();
      // Traiter chaque membre
      int count = 0;
      for (final membreData in membresList) {
        try {
          final membre = MembreModel.fromJson(membreData);
          await _membreBox.put(membre.id, membre);
          count++;
        } catch (e) {
          debugPrint('Erreur lors du traitement d\'un membre: $e');
        }
      }

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

  // Récupérer les membres depuis l'API
  Future<List<MembreModel>> fetchMembres() async {
    _isLoading = true;
    notifyListeners();

    try {
      final response = await ApiService.instance.get('/users');

      if (response.statusCode == 200) {
        final membresData = response.data;
        await processMembresData(membresData);
        return getAllMembres();
      } else {
        debugPrint('Erreur lors de la récupération des membres: ${response.statusCode}');
        return [];
      }
    } catch (e) {
      debugPrint('Erreur lors de la récupération des membres: $e');
      return [];
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // === MÉTHODES DE FILTRAGE ET RECHERCHE ===

  // Filtrer les membres par nom
  List<MembreModel> searchMembresByName(String query) {
    if (query.isEmpty) {
      return getAllMembres();
    }

    final lowercaseQuery = query.toLowerCase();
    return _membreBox.values
        .where(
            (membre) => (membre.name?.toLowerCase().contains(lowercaseQuery) ?? false) || (membre.firstName?.toLowerCase().contains(lowercaseQuery) ?? false))
        .toList();
  }

  // Filtrer les membres actifs
  List<MembreModel> getActiveMembres() {
    return _membreBox.values.where((membre) => membre.isActive == true).toList();
  }

  // Vider la boîte des membres
  Future<void> clearMembres() async {
    await _membreBox.clear();
    resetCache(); // Réinitialiser le cache après suppression de toutes les données
    notifyListeners();
  }
}
