import 'dart:io';
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:path_provider/path_provider.dart';
import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:geosector_app/core/services/hive_web_fix.dart';
import 'package:geosector_app/core/services/hive_adapters.dart';

// Import de tous les modèles typés
import 'package:geosector_app/core/data/models/user_model.dart';
import 'package:geosector_app/core/data/models/amicale_model.dart';
import 'package:geosector_app/core/data/models/client_model.dart';
import 'package:geosector_app/core/data/models/operation_model.dart';
import 'package:geosector_app/core/data/models/sector_model.dart';
import 'package:geosector_app/core/data/models/passage_model.dart';
import 'package:geosector_app/core/data/models/membre_model.dart';
import 'package:geosector_app/core/data/models/user_sector_model.dart';
import 'package:geosector_app/core/data/models/pending_request.dart';
import 'package:geosector_app/chat/models/room.dart';
import 'package:geosector_app/chat/models/message.dart';

/// Service singleton centralisé pour la gestion complète des Box Hive
/// Utilisé par main.dart pour l'initialisation et par logout pour le nettoyage
class HiveService {
  static HiveService? _instance;
  static HiveService get instance => _instance ??= HiveService._internal();
  HiveService._internal();

  /// Configuration des Box typées de l'application
  static const List<HiveBoxConfig> _boxConfigs = [
    HiveBoxConfig<UserModel>(AppKeys.userBoxName, 'UserModel'),
    HiveBoxConfig<AmicaleModel>(AppKeys.amicaleBoxName, 'AmicaleModel'),
    HiveBoxConfig<ClientModel>(AppKeys.clientsBoxName, 'ClientModel'),
    HiveBoxConfig<OperationModel>(AppKeys.operationsBoxName, 'OperationModel'),
    HiveBoxConfig<SectorModel>(AppKeys.sectorsBoxName, 'SectorModel'),
    HiveBoxConfig<PassageModel>(AppKeys.passagesBoxName, 'PassageModel'),
    HiveBoxConfig<MembreModel>(AppKeys.membresBoxName, 'MembreModel'),
    HiveBoxConfig<UserSectorModel>(AppKeys.userSectorBoxName, 'UserSectorModel'),
    // Chat boxes
    HiveBoxConfig<Room>(AppKeys.chatRoomsBoxName, 'Room'),
    HiveBoxConfig<Message>(AppKeys.chatMessagesBoxName, 'Message'),
    // Queue offline boxes
    HiveBoxConfig<PendingRequest>(AppKeys.pendingRequestsBoxName, 'PendingRequest'),
    HiveBoxConfig<dynamic>(AppKeys.tempEntitiesBoxName, 'TempEntities'),
    // Dynamic boxes
    HiveBoxConfig<dynamic>(AppKeys.settingsBoxName, 'Settings'),
    HiveBoxConfig<dynamic>(AppKeys.regionsBoxName, 'Regions'),
  ];

  bool _isInitialized = false;
  bool get isInitialized => _isInitialized;

  // === INITIALISATION LÉGÈRE POUR F5 (préserve les données) ===

  /// Initialisation légère de Hive SANS destruction des données
  /// Utilisée pour le F5 sur Web afin de vérifier si une session existe
  /// Retourne true si l'initialisation a réussi et qu'une session utilisateur existe
  Future<bool> initializeWithoutReset() async {
    try {
      debugPrint('🔧 Initialisation légère de Hive (préservation des données)...');

      // 1. Initialisation de base de Hive (idempotent)
      await Hive.initFlutter();
      debugPrint('✅ Hive.initFlutter() terminé');

      // 2. Enregistrement des adaptateurs (idempotent)
      _registerAdapters();

      // 3. Ouvrir les boxes SANS les détruire
      await _createAllBoxes();

      // 4. Vérifier si une session utilisateur existe
      bool hasSession = false;
      try {
        if (Hive.isBoxOpen(AppKeys.settingsBoxName)) {
          final settingsBox = Hive.box(AppKeys.settingsBoxName);
          final userId = settingsBox.get('current_user_id');
          if (userId != null) {
            // Vérifier que l'utilisateur existe dans la box user
            if (Hive.isBoxOpen(AppKeys.userBoxName)) {
              final userBox = Hive.box<UserModel>(AppKeys.userBoxName);
              final user = userBox.get(userId);
              if (user != null && user.hasValidSession) {
                hasSession = true;
                debugPrint('✅ Session utilisateur trouvée pour ID: $userId');
              }
            }
          }
        }
      } catch (e) {
        debugPrint('⚠️ Erreur vérification session: $e');
      }

      _isInitialized = true;
      debugPrint('✅ Initialisation légère terminée, session existante: $hasSession');
      return hasSession;
    } catch (e) {
      debugPrint('❌ Erreur lors de l\'initialisation légère: $e');
      return false;
    }
  }

  // === INITIALISATION COMPLÈTE (appelée par main.dart) ===

  /// Initialisation complète de Hive avec réinitialisation totale
  Future<void> initializeAndResetHive() async {
    if (_isInitialized) {
      debugPrint('ℹ️ HiveService déjà initialisé');
      return;
    }

    try {
      debugPrint('🔧 Initialisation complète de Hive avec reset...');

      // 1. Initialisation de base de Hive
      await Hive.initFlutter();
      debugPrint('✅ Hive.initFlutter() terminé');

      // 2. Enregistrement des adaptateurs
      _registerAdapters();

      // 3. Destruction complète des anciennes données
      await _destroyAllData();

      // 4. Création des Box vides et propres
      await _createAllBoxes();

      _isInitialized = true;
      debugPrint('✅ HiveService initialisé avec succès');
    } catch (e) {
      debugPrint('❌ Erreur lors de l\'initialisation complète: $e');
      _isInitialized = false;
      rethrow;
    }
  }

  // === INITIALISATION SIMPLE (appelée par splash_page si besoin) ===

  /// Initialisation simple sans reset (utilisée par splash_page si déjà initialisé)
  Future<void> ensureBoxesAreOpen() async {
    try {
      debugPrint('🔍 Vérification et ouverture des Box...');

      // Vérifier si toutes les Box sont ouvertes
      bool allOpen = true;
      for (final config in _boxConfigs) {
        if (!Hive.isBoxOpen(config.name)) {
          allOpen = false;
          break;
        }
      }

      if (allOpen) {
        debugPrint('✅ Toutes les Box sont déjà ouvertes');
        return;
      }

      // Ouvrir les Box manquantes
      await _createAllBoxes();
      debugPrint('✅ Box manquantes ouvertes');
    } catch (e) {
      debugPrint('❌ Erreur lors de la vérification des Box: $e');
      rethrow;
    }
  }

  // === NETTOYAGE LOGOUT (appelé lors du logout) ===

  /// Nettoyage sélectif lors du logout (préserve les utilisateurs)
  Future<void> cleanDataOnLogout() async {
    try {
      debugPrint('🧹 Nettoyage des données au logout...');

      // Nettoyer toutes les Box sauf les utilisateurs
      for (final config in _boxConfigs) {
        if (config.name != AppKeys.userBoxName) {
          await _clearSingleBox(config.name);
        }
      }

      debugPrint('✅ Nettoyage logout terminé (utilisateurs préservés)');
    } catch (e) {
      debugPrint('❌ Erreur lors du nettoyage logout: $e');
      rethrow;
    }
  }

  // === MÉTHODES PRIVÉES D'INITIALISATION ===

  /// Enregistrement de tous les adaptateurs Hive
  void _registerAdapters() {
    try {
      if (!Hive.isAdapterRegistered(0)) {
        // Utiliser HiveAdapters existant pour enregistrer tous les adaptateurs
        HiveAdapters.registerAll();
        debugPrint('🔌 Adaptateurs Hive enregistrés via HiveAdapters');
      } else {
        debugPrint('ℹ️ Adaptateurs déjà enregistrés');
      }
    } catch (e) {
      debugPrint('❌ Erreur enregistrement adaptateurs: $e');
      // Ne pas faire échouer l'initialisation
    }
  }

  /// Destruction complète de toutes les données selon la plateforme
  Future<void> _destroyAllData() async {
    try {
      debugPrint('💥 Destruction complète des données Hive...');

      // PROTECTION CRITIQUE : Vérifier la box pending_requests
      if (Hive.isBoxOpen(AppKeys.pendingRequestsBoxName)) {
        final pendingBox = Hive.box(AppKeys.pendingRequestsBoxName);
        if (pendingBox.isNotEmpty) {
          debugPrint('⚠️ ATTENTION: ${pendingBox.length} requêtes en attente trouvées dans pending_requests');
          debugPrint('⚠️ Cette box NE SERA PAS supprimée pour préserver les données');
          // On ne supprime PAS cette box si elle contient des données
        }
      }

      // 1. Fermer toutes les Box ouvertes
      await _closeAllOpenBoxes();

      // 2. Suppression selon la plateforme
      if (kIsWeb) {
        await _destroyDataWeb();
      } else if (Platform.isIOS) {
        await _destroyDataIOS();
      } else if (Platform.isAndroid) {
        await _destroyDataAndroid();
      } else {
        await _destroyDataDesktop();
      }

      // 3. Attendre pour s'assurer que tout est détruit
      await Future.delayed(const Duration(seconds: 1));

      debugPrint('✅ Destruction complète terminée');
    } catch (e) {
      debugPrint('❌ Erreur destruction: $e');
      // Continuer malgré l'erreur
    }
  }

  /// Fermeture de toutes les Box ouvertes
  Future<void> _closeAllOpenBoxes() async {
    try {
      debugPrint('🔒 Fermeture de toutes les Box ouvertes...');

      // Fermer les Box configurées
      for (final config in _boxConfigs) {
        try {
          if (Hive.isBoxOpen(config.name)) {
            await Hive.box(config.name).close();
            debugPrint('🔒 Box ${config.name} fermée');
          }
        } catch (e) {
          debugPrint('⚠️ Erreur fermeture ${config.name}: $e');
        }
      }

      // Fermer aussi les Box potentiellement orphelines
      final orphanBoxes = ['auth', 'temp', 'cache', 'locations', 'messages'];
      for (final boxName in orphanBoxes) {
        try {
          if (Hive.isBoxOpen(boxName)) {
            await Hive.box(boxName).close();
            debugPrint('🔒 Box orpheline $boxName fermée');
          }
        } catch (e) {
          debugPrint('⚠️ Erreur fermeture orpheline $boxName: $e');
        }
      }
    } catch (e) {
      debugPrint('❌ Erreur fermeture générale: $e');
    }
  }

  /// Destruction des données sur Web
  Future<void> _destroyDataWeb() async {
    try {
      debugPrint('🌐 Destruction Web...');

      // Sur Web, utiliser le HiveWebFix si disponible
      try {
        await HiveWebFix.resetHiveCompletely();
        debugPrint('✅ Destruction Web via HiveWebFix');
        return;
      } catch (e) {
        debugPrint('⚠️ HiveWebFix échoué, fallback...');
      }

      // Fallback : supprimer Box par Box
      for (final config in _boxConfigs) {
        try {
          await Hive.deleteBoxFromDisk(config.name);
          debugPrint('🗑️ Box Web ${config.name} supprimée');
        } catch (e) {
          debugPrint('⚠️ Erreur suppression Web ${config.name}: $e');
        }
      }
    } catch (e) {
      debugPrint('❌ Erreur destruction Web: $e');
    }
  }

  /// Destruction des données sur iOS
  Future<void> _destroyDataIOS() async {
    try {
      debugPrint('🍎 Destruction iOS...');

      // Méthode 1: Destruction totale
      try {
        await Hive.deleteFromDisk();
        debugPrint('✅ Destruction iOS complète');
        return;
      } catch (e) {
        debugPrint('⚠️ Destruction iOS totale échouée, méthode alternative...');
      }

      // Méthode 2: Suppression des fichiers manuellement
      try {
        final appDir = await getApplicationDocumentsDirectory();
        final hiveDir = Directory('${appDir.path}/hive');

        if (await hiveDir.exists()) {
          await hiveDir.delete(recursive: true);
          debugPrint('✅ Dossier Hive iOS supprimé');
        }
      } catch (e) {
        debugPrint('⚠️ Suppression dossier iOS échouée: $e');
      }

      // Méthode 3: Fallback Box par Box
      await _fallbackDeleteBoxes();
    } catch (e) {
      debugPrint('❌ Erreur destruction iOS: $e');
    }
  }

  /// Destruction des données sur Android
  Future<void> _destroyDataAndroid() async {
    try {
      debugPrint('🤖 Destruction Android...');

      // Méthode 1: Destruction totale
      try {
        await Hive.deleteFromDisk();
        debugPrint('✅ Destruction Android complète');
        return;
      } catch (e) {
        debugPrint('⚠️ Destruction Android totale échouée, méthode alternative...');
      }

      // Méthode 2: Suppression des fichiers .hive et .lock
      try {
        final appDir = await getApplicationDocumentsDirectory();
        final files = await appDir.list().toList();

        int deletedCount = 0;
        for (final file in files) {
          final fileName = file.path.split('/').last;
          if (fileName.endsWith('.hive') || fileName.endsWith('.lock')) {
            try {
              await file.delete();
              deletedCount++;
            } catch (e) {
              debugPrint('⚠️ Erreur suppression fichier $fileName: $e');
            }
          }
        }

        debugPrint('✅ $deletedCount fichiers Android supprimés');
      } catch (e) {
        debugPrint('⚠️ Suppression fichiers Android échouée: $e');
      }

      // Méthode 3: Fallback Box par Box
      await _fallbackDeleteBoxes();
    } catch (e) {
      debugPrint('❌ Erreur destruction Android: $e');
    }
  }

  /// Destruction des données sur Desktop
  Future<void> _destroyDataDesktop() async {
    try {
      debugPrint('🖥️ Destruction Desktop...');

      // Destruction totale
      await Hive.deleteFromDisk();
      debugPrint('✅ Destruction Desktop complète');
    } catch (e) {
      debugPrint('⚠️ Destruction Desktop échouée, fallback...');
      await _fallbackDeleteBoxes();
    }
  }

  /// Fallback : suppression Box par Box
  Future<void> _fallbackDeleteBoxes() async {
    debugPrint('🔄 Fallback: suppression Box par Box...');

    for (final config in _boxConfigs) {
      try {
        // PROTECTION : Ne pas supprimer pending_requests si elle contient des données
        if (config.name == AppKeys.pendingRequestsBoxName) {
          if (Hive.isBoxOpen(AppKeys.pendingRequestsBoxName)) {
            final box = Hive.box(AppKeys.pendingRequestsBoxName);
            if (box.isNotEmpty) {
              debugPrint('⏭️ Box ${config.name} ignorée (contient ${box.length} requêtes en attente)');
              continue;
            }
          }
        }
        
        await Hive.deleteBoxFromDisk(config.name);
        debugPrint('🗑️ Box fallback ${config.name} supprimée');
      } catch (e) {
        debugPrint('⚠️ Erreur suppression fallback ${config.name}: $e');
      }
    }
  }

  /// Création de toutes les Box vides et propres
  Future<void> _createAllBoxes() async {
    try {
      debugPrint('🆕 Création de toutes les Box...');

      for (int i = 0; i < _boxConfigs.length; i++) {
        final config = _boxConfigs[i];

        try {
          // Ajouter un timeout de 10 secondes pour éviter les blocages infinis
          await _createSingleBox(config).timeout(
            const Duration(seconds: 10),
            onTimeout: () {
              throw TimeoutException('Timeout lors de la création de la box ${config.name}');
            },
          );
          debugPrint('✅ Box ${config.name} créée (${i + 1}/${_boxConfigs.length})');
        } catch (e) {
          debugPrint('❌ Erreur création ${config.name}: $e');
          // Continuer même en cas d'erreur
        }

        // Petite pause entre les créations
        await Future.delayed(const Duration(milliseconds: 100));
      }

      debugPrint('✅ Toutes les Box ont été créées');
    } catch (e) {
      debugPrint('❌ Erreur création des Box: $e');
      rethrow;
    }
  }

  /// Création d'une Box individuelle avec le bon type
  Future<void> _createSingleBox(HiveBoxConfig config) async {
    try {
      if (Hive.isBoxOpen(config.name)) {
        debugPrint('ℹ️ Box ${config.name} déjà ouverte');
        return;
      }

      switch (config.type) {
        case 'UserModel':
          await Hive.openBox<UserModel>(config.name);
          break;
        case 'AmicaleModel':
          await Hive.openBox<AmicaleModel>(config.name);
          break;
        case 'ClientModel':
          await Hive.openBox<ClientModel>(config.name);
          break;
        case 'OperationModel':
          await Hive.openBox<OperationModel>(config.name);
          break;
        case 'SectorModel':
          await Hive.openBox<SectorModel>(config.name);
          break;
        case 'PassageModel':
          await Hive.openBox<PassageModel>(config.name);
          break;
        case 'MembreModel':
          await Hive.openBox<MembreModel>(config.name);
          break;
        case 'UserSectorModel':
          await Hive.openBox<UserSectorModel>(config.name);
          break;
        case 'Room':
          await Hive.openBox<Room>(config.name);
          break;
        case 'Message':
          await Hive.openBox<Message>(config.name);
          break;
        case 'PendingRequest':
          await Hive.openBox<PendingRequest>(config.name);
          break;
        case 'TempEntities':
          // Box dynamique pour stocker les entités temporaires
          await Hive.openBox(config.name);
          break;
        default:
          // Pour Settings, Regions, etc.
          await Hive.openBox(config.name);
      }
    } catch (e) {
      debugPrint('❌ Erreur création spécifique ${config.name}: $e');
      // Fallback : essayer sans type
      try {
        await Hive.openBox(config.name);
        debugPrint('⚠️ Box ${config.name} créée sans type');
      } catch (e2) {
        debugPrint('❌ Échec total ${config.name}: $e2');
        rethrow;
      }
    }
  }


  // === MÉTHODES UTILITAIRES ===

  /// Vider une Box individuelle
  Future<void> _clearSingleBox(String boxName) async {
    try {
      if (Hive.isBoxOpen(boxName)) {
        // Récupérer la configuration pour connaître le type
        final config = _boxConfigs.firstWhere(
          (c) => c.name == boxName,
          orElse: () => HiveBoxConfig(boxName, 'dynamic'),
        );
        
        // Utiliser la box typée selon le modèle
        switch (config.type) {
          case 'UserModel':
            await Hive.box<UserModel>(boxName).clear();
            break;
          case 'AmicaleModel':
            await Hive.box<AmicaleModel>(boxName).clear();
            break;
          case 'ClientModel':
            await Hive.box<ClientModel>(boxName).clear();
            break;
          case 'OperationModel':
            await Hive.box<OperationModel>(boxName).clear();
            break;
          case 'SectorModel':
            await Hive.box<SectorModel>(boxName).clear();
            break;
          case 'PassageModel':
            await Hive.box<PassageModel>(boxName).clear();
            break;
          case 'MembreModel':
            await Hive.box<MembreModel>(boxName).clear();
            break;
          case 'UserSectorModel':
            await Hive.box<UserSectorModel>(boxName).clear();
            break;
          case 'Room':
            await Hive.box<Room>(boxName).clear();
            break;
          case 'Message':
            await Hive.box<Message>(boxName).clear();
            break;
          case 'PendingRequest':
            // ATTENTION : Ne jamais vider pending_requests si elle contient des données critiques
            final pendingBox = Hive.box<PendingRequest>(boxName);
            if (pendingBox.isNotEmpty) {
              debugPrint('⚠️ ATTENTION: Box $boxName contient ${pendingBox.length} requêtes - Vidage ignoré');
              return; // Ne pas vider cette box
            }
            await pendingBox.clear();
            break;
          case 'TempEntities':
            await Hive.box(boxName).clear();
            break;
          default:
            // Pour les box non typées (settings, regions, etc.)
            await Hive.box(boxName).clear();
            break;
        }
        debugPrint('🧹 Box $boxName vidée');
      } else {
        debugPrint('ℹ️ Box $boxName n\'est pas ouverte, impossible de la vider');
      }
    } catch (e) {
      debugPrint('⚠️ Erreur vidage $boxName: $e');
    }
  }

  /// Vérification que toutes les Box sont ouvertes
  bool areAllBoxesOpen() {
    for (final config in _boxConfigs) {
      if (!Hive.isBoxOpen(config.name)) {
        debugPrint('❌ Box ${config.name} n\'est pas ouverte');
        return false;
      }
    }
    debugPrint('✅ Toutes les Box sont ouvertes');
    return true;
  }

  /// Vérification rapide que les boxes critiques sont initialisées
  /// Utilisé par LoginPage pour détecter si une redirection vers SplashPage est nécessaire
  bool areBoxesInitialized() {
    try {
      // Vérifier seulement les boxes critiques pour le login
      final criticalBoxes = [
        AppKeys.userBoxName,     // Nécessaire pour getCurrentUser
        AppKeys.membresBoxName,   // Nécessaire pour le pré-remplissage
        AppKeys.settingsBoxName,  // Nécessaire pour les préférences
      ];
      
      for (final boxName in criticalBoxes) {
        if (!Hive.isBoxOpen(boxName)) {
          debugPrint('⚠️ Box critique non ouverte: $boxName');
          return false;
        }
      }
      
      // Vérifier aussi le flag d'initialisation
      if (!_isInitialized) {
        debugPrint('⚠️ HiveService non initialisé');
        return false;
      }
      
      return true;
    } catch (e) {
      debugPrint('❌ Erreur vérification boxes: $e');
      return false;
    }
  }

  /// Récupération sécurisée d'une Box typée
  Box<T> getTypedBox<T>(String boxName) {
    if (!Hive.isBoxOpen(boxName)) {
      throw Exception('La Box $boxName n\'est pas ouverte');
    }
    return Hive.box<T>(boxName);
  }

  /// Récupération sécurisée d'une Box non-typée
  Box getBox(String boxName) {
    if (!Hive.isBoxOpen(boxName)) {
      throw Exception('La Box $boxName n\'est pas ouverte');
    }
    return Hive.box(boxName);
  }

  /// Liste des noms de toutes les Box configurées
  List<String> getAllBoxNames() {
    return _boxConfigs.map((config) => config.name).toList();
  }

  /// Diagnostic complet de l'état des Box
  Map<String, bool> getDiagnostic() {
    final diagnostic = <String, bool>{};
    for (final config in _boxConfigs) {
      diagnostic[config.name] = Hive.isBoxOpen(config.name);
    }
    return diagnostic;
  }

  /// Reset complet du service (pour tests)
  static void reset() {
    _instance = null;
  }
}

/// Configuration d'une Box Hive avec type
class HiveBoxConfig<T> {
  final String name;
  final String type;

  const HiveBoxConfig(this.name, this.type);
}
