import 'package:flutter/foundation.dart'; import 'package:em2rp/models/equipment_model.dart'; import 'package:em2rp/services/data_service.dart'; import 'package:em2rp/services/api_service.dart'; class EquipmentProvider extends ChangeNotifier { final DataService _dataService = DataService(FirebaseFunctionsApiService()); List _equipment = []; List _models = []; List _brands = []; EquipmentCategory? _selectedCategory; EquipmentStatus? _selectedStatus; String? _selectedModel; String _searchQuery = ''; bool _isLoading = false; bool _isInitialized = false; // Flag pour savoir si les équipements ont été chargés // Constructeur - Ne charge PAS automatiquement // Les équipements seront chargés à la demande (page de gestion ou via getEquipmentsByIds) EquipmentProvider(); // Getters List get equipment => _filteredEquipment; List get allEquipment => _equipment; // Tous les équipements sans filtre List get models => _models; List 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 isInitialized => _isInitialized; /// S'assure que les équipements sont chargés (charge si nécessaire) Future ensureLoaded() async { if (_isInitialized || _isLoading) { print('[EquipmentProvider] Equipment already loaded or loading, skipping...'); return; } print('[EquipmentProvider] Equipment not loaded, loading now...'); await loadEquipments(); } /// Charger tous les équipements via l'API (utilisé par la page de gestion) Future loadEquipments() async { print('[EquipmentProvider] Starting to load equipments...'); _isLoading = true; notifyListeners(); try { print('[EquipmentProvider] Calling getEquipments API...'); final equipmentsData = await _dataService.getEquipments(); print('[EquipmentProvider] Received ${equipmentsData.length} equipments from API'); _equipment = equipmentsData.map((data) { return EquipmentModel.fromMap(data, data['id'] as String); }).toList(); print('[EquipmentProvider] Mapped ${_equipment.length} equipment models'); // Extraire les modèles et marques uniques _extractUniqueValues(); _isInitialized = true; _isLoading = false; notifyListeners(); print('[EquipmentProvider] Equipment loading complete'); } 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> getEquipmentsByIds(List equipmentIds) async { if (equipmentIds.isEmpty) return []; print('[EquipmentProvider] Loading ${equipmentIds.length} equipments by IDs...'); try { // Vérifier d'abord le cache local final cachedEquipments = []; final missingIds = []; 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) { return EquipmentModel.fromMap(data, data['id'] as String); }).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 = {}; final brandSet = {}; 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 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; } /// Définir le filtre de catégorie void setSelectedCategory(EquipmentCategory? category) { _selectedCategory = category; notifyListeners(); } /// Définir le filtre de statut void setSelectedStatus(EquipmentStatus? status) { _selectedStatus = status; notifyListeners(); } /// Définir le filtre de modèle void setSelectedModel(String? model) { _selectedModel = model; notifyListeners(); } /// Définir la requête de recherche void setSearchQuery(String query) { _searchQuery = query; notifyListeners(); } /// Réinitialiser tous les filtres void clearFilters() { _selectedCategory = null; _selectedStatus = null; _selectedModel = null; _searchQuery = ''; notifyListeners(); } /// Recharger les équipements Future refresh() async { await loadEquipments(); } // === MÉTHODES STREAM (COMPATIBILITÉ) === /// Stream des équipements (pour compatibilité avec ancien code) Stream> get equipmentStream async* { yield _equipment; } /// Supprimer un équipement Future deleteEquipment(String equipmentId) async { try { await _dataService.deleteEquipment(equipmentId); await loadEquipments(); // Recharger la liste } catch (e) { print('Error deleting equipment: $e'); rethrow; } } /// Ajouter un équipement Future addEquipment(EquipmentModel equipment) async { try { await _dataService.createEquipment(equipment.id, equipment.toMap()); await loadEquipments(); // Recharger la liste } catch (e) { print('Error adding equipment: $e'); rethrow; } } /// Mettre à jour un équipement Future updateEquipment(EquipmentModel equipment) async { try { await _dataService.updateEquipment(equipment.id, equipment.toMap()); await loadEquipments(); // Recharger la liste } catch (e) { print('Error updating equipment: $e'); rethrow; } } /// Charger les marques Future loadBrands() async { // Les marques sont déjà chargées avec loadEquipments _extractUniqueValues(); } /// Charger les modèles Future loadModels() async { // Les modèles sont déjà chargés avec loadEquipments _extractUniqueValues(); } /// Charger les modèles d'une marque spécifique Future> loadModelsByBrand(String brand) async { // Filtrer les modèles par marque final modelsByBrand = _equipment .where((eq) => eq.brand == brand && eq.model != null) .map((eq) => eq.model!) .toSet() .toList(); return modelsByBrand; } /// Charger les sous-catégories d'une catégorie spécifique Future> loadSubCategoriesByCategory(EquipmentCategory category) async { // Filtrer les sous-catégories par catégorie final subCategoriesByCategory = _equipment .where((eq) => eq.category == category && eq.subCategory != null && eq.subCategory!.isNotEmpty) .map((eq) => eq.subCategory!) .toSet() .toList() ..sort(); return subCategoriesByCategory; } /// Calculer le statut réel d'un équipement (compatibilité) Future calculateRealStatus(EquipmentModel equipment) async { // Pour l'instant, retourner le statut stocké // TODO: Implémenter le calcul réel si nécessaire return equipment.status; } }