import 'package:flutter/foundation.dart';
import 'dart:async';
import 'package:em2rp/models/equipment_model.dart';
import 'package:em2rp/services/data_service.dart';
import 'package:em2rp/services/api_service.dart';
import 'package:em2rp/utils/debug_log.dart';

class EquipmentProvider extends ChangeNotifier {
  final DataService _dataService = DataService(FirebaseFunctionsApiService());

  // Timer pour le debouncing de la recherche
  Timer? _searchDebounceTimer;

  // Liste paginée pour la page de gestion
  final List<EquipmentModel> _paginatedEquipment = [];
  bool _hasMore = true;
  bool _isLoadingMore = false;
  String? _lastVisible;

  // Cache complet pour getEquipmentsByIds et compatibilité
  final List<EquipmentModel> _equipment = [];
  List<String> _models = [];
  List<String> _brands = [];

  // Filtres et recherche
  EquipmentCategory? _selectedCategory;
  EquipmentStatus? _selectedStatus;
  String? _selectedModel;
  String _searchQuery = '';
  bool _isLoading = false;
  bool _isInitialized = false;
  bool _isFullListLoaded = false;

  // Mode de chargement (pagination vs full)
  bool _usePagination = false;

  EquipmentProvider();

  // Getters
  List<EquipmentModel> get equipment => _usePagination ? _paginatedEquipment : _filteredEquipment;
  List<EquipmentModel> get allEquipment => _equipment;
  List<String> get models => _models;
  List<String> get brands => _brands;
  EquipmentCategory? get selectedCategory => _selectedCategory;
  EquipmentStatus? get selectedStatus => _selectedStatus;
  String? get selectedModel => _selectedModel;
  String get searchQuery => _searchQuery;
  bool get isLoading => _isLoading;
  bool get isLoadingMore => _isLoadingMore;
  bool get hasMore => _hasMore;
  bool get isInitialized => _isInitialized;
  bool get isFullListLoaded => _isFullListLoaded;
  bool get usePagination => _usePagination;

  /// S'assure que les équipements sont chargés (charge si nécessaire)
  Future<void> ensureLoaded() async {
    // Si déjà en train de charger, attendre
    if (_isLoading) {
      print('[EquipmentProvider] Equipment loading in progress, waiting...');
      return;
    }

    // Si déjà initialisé avec le cache complet des données, ne rien faire
    if (_isFullListLoaded) {
      print('[EquipmentProvider] Equipment already loaded (${_equipment.length} items), skipping...');
      return;
    }

    print('[EquipmentProvider] Equipment not loaded, loading now...');
    await loadEquipments();
  }

  /// Charger tous les équipements via l'API (utilisé par les dialogs et sélection)
  Future<void> loadEquipments() async {
    print('[EquipmentProvider] Starting to load ALL equipments...');
    _isLoading = true;
    scheduleMicrotask(notifyListeners);

    try {
      _equipment.clear();
      String? lastVisible;
      bool hasMore = true;
      int pageCount = 0;

      // Charger toutes les pages en boucle
      while (hasMore) {
        pageCount++;
        print('[EquipmentProvider] Loading page $pageCount...');

        final result = await _dataService.getEquipmentsPaginated(
          limit: 100, // Charger 100 par page pour aller plus vite
          startAfter: lastVisible,
          sortBy: 'id',
          sortOrder: 'asc',
        );

        final equipmentsData = result['equipments'] as List<dynamic>;
        print('[EquipmentProvider] Page $pageCount: ${equipmentsData.length} equipments');

        final pageEquipments = equipmentsData.map((data) {
          final id = data['id'] as String;
          return EquipmentModel.fromMap(data as Map<String, dynamic>, id);
        }).toList();

        _equipment.addAll(pageEquipments);

        hasMore = result['hasMore'] as bool? ?? false;
        lastVisible = result['lastVisible'] as String?;

        if (!hasMore) {
          print('[EquipmentProvider] All pages loaded. Total: ${_equipment.length} equipments');
        }
      }

      // Extraire les modèles et marques uniques
      _extractUniqueValues();
      _isFullListLoaded = true;
      _isInitialized = true;
      _isLoading = false;
      notifyListeners();
      print('[EquipmentProvider] Equipment loading complete: ${_equipment.length} equipments');
    } catch (e) {
      print('[EquipmentProvider] Error loading equipments: $e');
      _isLoading = false;
      notifyListeners();
      rethrow;
    }
  }

  /// Charge plusieurs équipements par leurs IDs (optimisé pour les détails d'événement)
  Future<List<EquipmentModel>> getEquipmentsByIds(List<String> equipmentIds) async {
    if (equipmentIds.isEmpty) return [];

    print('[EquipmentProvider] Loading ${equipmentIds.length} equipments by IDs...');

    try {
      // Vérifier d'abord le cache local
      final cachedEquipments = <EquipmentModel>[];
      final missingIds = <String>[];

      for (final id in equipmentIds) {
        final cached = _equipment.firstWhere(
          (eq) => eq.id == id,
          orElse: () => EquipmentModel(
            id: '',
            name: '',
            category: EquipmentCategory.other,
            status: EquipmentStatus.available,
            maintenanceIds: [],
            createdAt: DateTime.now(),
            updatedAt: DateTime.now(),
          ),
        );

        if (cached.id.isNotEmpty) {
          cachedEquipments.add(cached);
        } else {
          missingIds.add(id);
        }
      }

      print('[EquipmentProvider] Found ${cachedEquipments.length} in cache, ${missingIds.length} missing');

      // Si tous sont en cache, retourner directement
      if (missingIds.isEmpty) {
        return cachedEquipments;
      }

      // Charger les manquants depuis l'API
      final equipmentsData = await _dataService.getEquipmentsByIds(missingIds);

      final loadedEquipments = equipmentsData.map((data) {
        final id = data['id'] as String; // L'ID vient du backend
        return EquipmentModel.fromMap(data, id);
      }).toList();

      // Ajouter au cache
      for (final eq in loadedEquipments) {
        if (!_equipment.any((e) => e.id == eq.id)) {
          _equipment.add(eq);
        }
      }

      print('[EquipmentProvider] Loaded ${loadedEquipments.length} equipments from API');

      // Retourner tous les équipements (cache + chargés)
      return [...cachedEquipments, ...loadedEquipments];
    } catch (e) {
      print('[EquipmentProvider] Error loading equipments by IDs: $e');
      rethrow;
    }
  }

  /// Extraire modèles et marques uniques
  void _extractUniqueValues() {
    final modelSet = <String>{};
    final brandSet = <String>{};

    for (final eq in _equipment) {
      if (eq.model != null && eq.model!.isNotEmpty) {
        modelSet.add(eq.model!);
      }
      if (eq.brand != null && eq.brand!.isNotEmpty) {
        brandSet.add(eq.brand!);
      }
    }

    _models = modelSet.toList()..sort();
    _brands = brandSet.toList()..sort();
  }

  /// Obtenir les équipements filtrés
  List<EquipmentModel> get _filteredEquipment {
    var filtered = _equipment;

    if (_selectedCategory != null) {
      filtered = filtered.where((eq) => eq.category == _selectedCategory).toList();
    }

    if (_selectedStatus != null) {
      filtered = filtered.where((eq) => eq.status == _selectedStatus).toList();
    }

    if (_selectedModel != null && _selectedModel!.isNotEmpty) {
      filtered = filtered.where((eq) => eq.model == _selectedModel).toList();
    }

    if (_searchQuery.isNotEmpty) {
      final query = _searchQuery.toLowerCase();
      filtered = filtered.where((eq) {
        return eq.name.toLowerCase().contains(query) ||
               eq.id.toLowerCase().contains(query) ||
               (eq.model?.toLowerCase().contains(query) ?? false) ||
               (eq.brand?.toLowerCase().contains(query) ?? false);
      }).toList();
    }

    return filtered;
  }

  // ============================================================================
  // PAGINATION - Nouvelles méthodes
  // ============================================================================

  /// Active le mode pagination (pour la page de gestion)
  void enablePagination() {
    if (!_usePagination) {
      _usePagination = true;
      DebugLog.info('[EquipmentProvider] Pagination mode enabled');
    }
  }

  /// Désactive le mode pagination (pour les autres pages)
  void disablePagination() {
    if (_usePagination) {
      _usePagination = false;
      DebugLog.info('[EquipmentProvider] Pagination mode disabled');
    }
  }

  /// Charge la première page (réinitialise tout)
  Future<void> loadFirstPage() async {
    DebugLog.info('[EquipmentProvider] Loading first page...');

    _paginatedEquipment.clear();
    _lastVisible = null;
    _hasMore = true;
    _isLoading = true;
    scheduleMicrotask(notifyListeners);

    try {
      await loadNextPage();
      _isInitialized = true;
    } catch (e) {
      DebugLog.error('[EquipmentProvider] Error loading first page', e);
      _isLoading = false;
      notifyListeners();
      rethrow;
    }
  }

  /// Charge la page suivante (scroll infini)
  Future<void> loadNextPage() async {
    if (_isLoadingMore || !_hasMore) {
      DebugLog.info('[EquipmentProvider] Skip loadNextPage: isLoadingMore=$_isLoadingMore, hasMore=$_hasMore');
      return;
    }

    DebugLog.info('[EquipmentProvider] Loading next page... (current: ${_paginatedEquipment.length})');

    _isLoadingMore = true;
    _isLoading = true;
    scheduleMicrotask(notifyListeners);

    try {
      final result = await _dataService.getEquipmentsPaginated(
        limit: 20,
        startAfter: _lastVisible,
        category: _selectedCategory?.name,
        status: _selectedStatus?.name,
        searchQuery: _searchQuery.isNotEmpty ? _searchQuery : null,
        sortBy: 'id',
        sortOrder: 'asc',
      );

      final newEquipments = (result['equipments'] as List<dynamic>)
          .map((data) {
            final map = data as Map<String, dynamic>;
            final id = map['id'] as String; // L'ID vient du backend dans le JSON
            return EquipmentModel.fromMap(map, id);
          })
          .toList();

      _paginatedEquipment.addAll(newEquipments);
      _hasMore = result['hasMore'] as bool? ?? false;
      _lastVisible = result['lastVisible'] as String?;

      DebugLog.info('[EquipmentProvider] Loaded ${newEquipments.length} equipments, total: ${_paginatedEquipment.length}, hasMore: $_hasMore');

      _isLoadingMore = false;
      _isLoading = false;
      notifyListeners();
    } catch (e) {
      DebugLog.error('[EquipmentProvider] Error loading next page', e);
      _isLoadingMore = false;
      _isLoading = false;
      notifyListeners();
      rethrow;
    }
  }

  /// Recharge en changeant de filtre ou recherche
  Future<void> reload() async {
    DebugLog.info('[EquipmentProvider] Reloading with new filters...');
    await loadFirstPage();
  }

  /// Définir le filtre de catégorie
  void setSelectedCategory(EquipmentCategory? category) async {
    if (_selectedCategory == category) return;
    _selectedCategory = category;
    if (_usePagination) {
      await reload();
    } else {
      notifyListeners();
    }
  }

  /// Définir le filtre de statut
  void setSelectedStatus(EquipmentStatus? status) async {
    if (_selectedStatus == status) return;
    _selectedStatus = status;
    if (_usePagination) {
      await reload();
    } else {
      notifyListeners();
    }
  }

  /// Définir le filtre de modèle
  void setSelectedModel(String? model) async {
    if (_selectedModel == model) return;
    _selectedModel = model;
    if (_usePagination) {
      await reload();
    } else {
      notifyListeners();
    }
  }

  /// Définir la requête de recherche (avec debouncing)
  void setSearchQuery(String query) {
    if (_searchQuery == query) return;
    _searchQuery = query;

    // Annuler le timer précédent
    _searchDebounceTimer?.cancel();

    if (_usePagination) {
      // Attendre 500ms avant de recharger (debouncing)
      _searchDebounceTimer = Timer(const Duration(milliseconds: 500), () {
        reload();
      });
    } else {
      notifyListeners();
    }
  }

  @override
  void dispose() {
    _searchDebounceTimer?.cancel();
    super.dispose();
  }

  /// Réinitialiser tous les filtres
  void clearFilters() async {
    _selectedCategory = null;
    _selectedStatus = null;
    _selectedModel = null;
    _searchQuery = '';
    if (_usePagination) {
      await reload();
    } else {
      notifyListeners();
    }
  }

  // ============================================================================
  // MÉTHODES COMPATIBILITÉ (pour ancien code)
  // ============================================================================

  /// Recharger les équipements (ancien système)
  Future<void> refresh() async {
    if (_usePagination) {
      await reload();
    } else {
      await loadEquipments();
    }
  }

  /// Stream des équipements (pour compatibilité avec ancien code)
  Stream<List<EquipmentModel>> get equipmentStream async* {
    if (!_isInitialized && !_usePagination) {
      await loadEquipments();
    }
    yield equipment;
  }

  /// Supprimer un équipement
  Future<void> deleteEquipment(String equipmentId, {bool forceDelete = false}) async {
    try {
      await _dataService.deleteEquipment(equipmentId, forceDelete: forceDelete);
      _isFullListLoaded = false;
      _equipment.clear();
      if (_usePagination) {
        await reload();
      } else {
        await loadEquipments();
      }
    } catch (e) {
      DebugLog.error('[EquipmentProvider] Error deleting equipment', e);
      rethrow;
    }
  }

  /// Ajouter un équipement
  Future<void> addEquipment(EquipmentModel equipment) async {
    try {
      await _dataService.createEquipment(equipment.id, equipment.toMap());
      _isFullListLoaded = false;
      _equipment.clear();
      if (_usePagination) {
        await reload();
      } else {
        await loadEquipments();
      }
    } catch (e) {
      DebugLog.error('[EquipmentProvider] Error adding equipment', e);
      rethrow;
    }
  }

  /// Mettre à jour un équipement
  Future<void> updateEquipment(EquipmentModel equipment) async {
    try {
      await _dataService.updateEquipment(equipment.id, equipment.toMap());
      _isFullListLoaded = false;
      _equipment.clear();
      if (_usePagination) {
        await reload();
      } else {
        await loadEquipments();
      }
    } catch (e) {
      DebugLog.error('[EquipmentProvider] Error updating equipment', e);
      rethrow;
    }
  }

  /// Charger les marques
  Future<void> loadBrands() async {
    await ensureLoaded();
    _extractUniqueValues();
  }

  /// Charger les modèles
  Future<void> loadModels() async {
    await ensureLoaded();
    _extractUniqueValues();
  }

  /// Charger les modèles d'une marque spécifique
  Future<List<String>> loadModelsByBrand(String brand) async {
    await ensureLoaded();
    return _equipment
        .where((eq) => eq.brand?.toLowerCase() == brand.toLowerCase())
        .map((eq) => eq.model ?? '')
        .where((model) => model.isNotEmpty)
        .toSet()
        .toList()
      ..sort();
  }

  /// Charger les sous-catégories d'une catégorie spécifique
  Future<List<String>> loadSubCategoriesByCategory(EquipmentCategory category) async {
    await ensureLoaded();
    return _equipment
        .where((eq) => eq.category == category)
        .map((eq) => eq.subCategory ?? '')
        .where((sub) => sub.isNotEmpty)
        .toSet()
        .toList()
      ..sort();
  }

  /// Calculer le statut réel d'un équipement (pour badge)
  EquipmentStatus calculateRealStatus(EquipmentModel equipment) {
    // Pour les consommables/câbles, vérifier le seuil critique
    if (equipment.category == EquipmentCategory.consumable ||
        equipment.category == EquipmentCategory.cable) {
      final availableQty = equipment.availableQuantity ?? 0;
      final criticalThreshold = equipment.criticalThreshold ?? 0;

      if (criticalThreshold > 0 && availableQty <= criticalThreshold) {
        return EquipmentStatus.maintenance; // Utiliser maintenance pour indiquer un problème
      }
    }

    // Sinon retourner le statut de base
    return equipment.status;
  }
}

