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

class ContainerProvider with ChangeNotifier {
  final ContainerService _containerService = ContainerService();
  final DataService _dataService = DataService(FirebaseFunctionsApiService());

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

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

  // Cache complet pour compatibilité
  final List<ContainerModel> _containers = [];

  // Filtres et recherche
  ContainerType? _selectedType;
  EquipmentStatus? _selectedStatus;
  String _searchQuery = '';
  bool _isLoading = false;
  bool _isInitialized = false;

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

  // Getters
  List<ContainerModel> get containers => _usePagination ? _paginatedContainers : _containers;
  ContainerType? get selectedType => _selectedType;
  EquipmentStatus? get selectedStatus => _selectedStatus;
  String get searchQuery => _searchQuery;
  bool get isLoading => _isLoading;
  bool get isLoadingMore => _isLoadingMore;
  bool get hasMore => _hasMore;
  bool get isInitialized => _isInitialized;
  bool get usePagination => _usePagination;

  /// S'assure que les conteneurs sont chargés (charge si nécessaire)
  Future<void> ensureLoaded() async {
    if (_isInitialized || _isLoading) {
      return;
    }
    await loadContainers();
  }

  /// Charger tous les containers via l'API (avec pagination automatique)
  Future<void> loadContainers() async {
    _isLoading = true;
    notifyListeners();

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

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

        final result = await _dataService.getContainersPaginated(
          limit: 100, // Charger 100 par page pour aller plus vite
          startAfter: lastVisible,
          sortBy: 'id',
          sortOrder: 'asc',
          type: _selectedType?.name,
          status: _selectedStatus?.name,
          searchQuery: _searchQuery,
        );

        final containers = (result['containers'] as List<dynamic>)
            .map((data) => ContainerModel.fromMap(data, data['id'] as String))
            .toList();

        _containers.addAll(containers);
        hasMore = result['hasMore'] as bool? ?? false;
        lastVisible = result['lastVisible'] as String?;

        DebugLog.info('[ContainerProvider] Loaded ${containers.length} containers, total: ${_containers.length}, hasMore: $hasMore');
      }

      _isLoading = false;
      _isInitialized = true;
      notifyListeners();
    } catch (e) {
      DebugLog.error('[ContainerProvider] Error loading containers', e);
      _isLoading = false;
      notifyListeners();
    }
  }

  /// Récupérer les containers avec filtres appliqués
  Future<List<ContainerModel>> getContainers() async {
    return await _containerService.getContainers(
      type: _selectedType,
      status: _selectedStatus,
      searchQuery: _searchQuery,
    );
  }

  /// Stream des containers - retourne un stream depuis les données en cache
  /// Pour compatibilité avec les widgets existants qui utilisent StreamBuilder
  Stream<List<ContainerModel>> get containersStream async* {
    // Si les données ne sont pas chargées, charger d'abord
    if (!_isInitialized) {
      await loadContainers();
    }

    // Émettre les données actuelles
    yield _containers;

    // Continuer à émettre les mises à jour du cache
    // Note: Pour un vrai temps réel, il faudrait implémenter un StreamController
    // et notifier quand les données changent
  }

  /// Définir le type sélectionné
  void setSelectedType(ContainerType? type) async {
    if (_selectedType == type) return;
    _selectedType = type;
    if (_usePagination) {
      await reload();
    } else {
      notifyListeners();
    }
  }

  /// Définir le statut sélectionné
  void setSelectedStatus(EquipmentStatus? status) async {
    if (_selectedStatus == status) return;
    _selectedStatus = status;
    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();
  }

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

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

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

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

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

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

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

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

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

    try {
      final result = await _dataService.getContainersPaginated(
        limit: 20,
        startAfter: _lastVisible,
        type: _selectedType != null ? containerTypeToString(_selectedType!) : null,
        searchQuery: _searchQuery.isNotEmpty ? _searchQuery : null,
        sortBy: 'id',
        sortOrder: 'asc',
      );

      final newContainers = (result['containers'] as List<dynamic>)
          .map((data) {
            final map = data as Map<String, dynamic>;
            return ContainerModel.fromMap(map, map['id'] as String);
          })
          .toList();

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

      DebugLog.info('[ContainerProvider] Loaded ${newContainers.length} containers, total: ${_paginatedContainers.length}, hasMore: $_hasMore');

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

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

  /// Créer un nouveau container
  Future<void> createContainer(ContainerModel container) async {
    await _containerService.createContainer(container);
    notifyListeners();
  }

  /// Mettre à jour un container
  Future<void> updateContainer(String id, Map<String, dynamic> data) async {
    await _containerService.updateContainer(id, data);
    notifyListeners();
  }

  /// Supprimer un container
  Future<void> deleteContainer(String id) async {
    await _containerService.deleteContainer(id);
    notifyListeners();
  }

  /// Récupérer un container par ID
  Future<ContainerModel?> getContainerById(String id) async {
    return await _containerService.getContainerById(id);
  }

  /// Charge plusieurs conteneurs par leurs IDs (optimisé pour les détails d'événement)
  Future<List<ContainerModel>> getContainersByIds(List<String> containerIds) async {
    if (containerIds.isEmpty) return [];

    DebugLog.info('[ContainerProvider] Loading ${containerIds.length} containers by IDs...');

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

      for (final id in containerIds) {
        final cached = _containers.firstWhere(
          (c) => c.id == id,
          orElse: () => ContainerModel(
            id: '',
            name: '',
            type: ContainerType.flightCase,
            status: EquipmentStatus.available,
            equipmentIds: [],
            createdAt: DateTime.now(),
            updatedAt: DateTime.now(),
          ),
        );

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

      DebugLog.info('[ContainerProvider] Found ${cachedContainers.length} in cache, ${missingIds.length} missing');

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

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

      final loadedContainers = containersData.map((data) {
        return ContainerModel.fromMap(data, data['id'] as String);
      }).toList();

      // Ajouter au cache
      for (final container in loadedContainers) {
        if (!_containers.any((c) => c.id == container.id)) {
          _containers.add(container);
        }
      }

      DebugLog.info('[ContainerProvider] Loaded ${loadedContainers.length} containers from API');

      // Retourner tous les conteneurs (cache + chargés)
      return [...cachedContainers, ...loadedContainers];
    } catch (e) {
      DebugLog.error('[ContainerProvider] Error loading containers by IDs', e);
      rethrow;
    }
  }

  /// Ajouter un équipement à un container
  Future<Map<String, dynamic>> addEquipmentToContainer({
    required String containerId,
    required String equipmentId,
    String? userId,
  }) async {
    final result = await _containerService.addEquipmentToContainer(
      containerId: containerId,
      equipmentId: equipmentId,
      userId: userId,
    );
    notifyListeners();
    return result;
  }

  /// Retirer un équipement d'un container
  Future<void> removeEquipmentFromContainer({
    required String containerId,
    required String equipmentId,
    String? userId,
  }) async {
    await _containerService.removeEquipmentFromContainer(
      containerId: containerId,
      equipmentId: equipmentId,
      userId: userId,
    );
    notifyListeners();
  }

  /// Vérifier la disponibilité d'un container
  Future<Map<String, dynamic>> checkContainerAvailability({
    required String containerId,
    required DateTime startDate,
    required DateTime endDate,
    String? excludeEventId,
  }) async {
    return await _containerService.checkContainerAvailability(
      containerId: containerId,
      startDate: startDate,
      endDate: endDate,
      excludeEventId: excludeEventId,
    );
  }

  /// Récupérer les équipements d'un container
  Future<List<EquipmentModel>> getContainerEquipment(String containerId) async {
    return await _containerService.getContainerEquipment(containerId);
  }

  /// Trouver tous les containers contenant un équipement
  Future<List<ContainerModel>> findContainersWithEquipment(String equipmentId) async {
    return await _containerService.findContainersWithEquipment(equipmentId);
  }

  /// Vérifier si un ID existe
  Future<bool> checkContainerIdExists(String id) async {
    return await _containerService.checkContainerIdExists(id);
  }

  /// Générer un ID unique pour un container
  /// Format: BOX_{TYPE}_{NAME}_{NUMBER}
  static String generateContainerId({
    required ContainerType type,
    required String name,
    int? number,
  }) {
    // Obtenir le type en majuscules
    final typeStr = containerTypeToString(type);

    // Nettoyer le nom (enlever espaces, caractères spéciaux)
    final cleanName = name
        .replaceAll(' ', '_')
        .replaceAll(RegExp(r'[^a-zA-Z0-9_-]'), '')
        .toUpperCase();

    if (number != null) {
      return 'BOX_${typeStr}_${cleanName}_#$number';
    }

    return 'BOX_${typeStr}_$cleanName';
  }

  /// Assurer l'unicité d'un ID de container
  static Future<String> ensureUniqueContainerId(
    String baseId,
    ContainerService service,
  ) async {
    String uniqueId = baseId;
    int counter = 1;

    while (await service.checkContainerIdExists(uniqueId)) {
      uniqueId = '${baseId}_$counter';
      counter++;
    }

    return uniqueId;
  }
}

