import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:em2rp/models/container_model.dart'; import 'package:em2rp/models/equipment_model.dart'; class ContainerService { final FirebaseFirestore _firestore = FirebaseFirestore.instance; // Collection references CollectionReference get _containersCollection => _firestore.collection('containers'); CollectionReference get _equipmentCollection => _firestore.collection('equipments'); // CRUD Operations /// Créer un nouveau container Future createContainer(ContainerModel container) async { try { await _containersCollection.doc(container.id).set(container.toMap()); } catch (e) { print('Error creating container: $e'); rethrow; } } /// Mettre à jour un container Future updateContainer(String id, Map data) async { try { data['updatedAt'] = Timestamp.fromDate(DateTime.now()); await _containersCollection.doc(id).update(data); } catch (e) { print('Error updating container: $e'); rethrow; } } /// Supprimer un container Future deleteContainer(String id) async { try { // Récupérer le container pour obtenir les équipements final container = await getContainerById(id); if (container != null && container.equipmentIds.isNotEmpty) { // Retirer le container des parentBoxIds de chaque équipement for (final equipmentId in container.equipmentIds) { final equipmentDoc = await _equipmentCollection.doc(equipmentId).get(); if (equipmentDoc.exists) { final equipment = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); final updatedParents = equipment.parentBoxIds.where((boxId) => boxId != id).toList(); await _equipmentCollection.doc(equipmentId).update({ 'parentBoxIds': updatedParents, 'updatedAt': Timestamp.fromDate(DateTime.now()), }); } } } await _containersCollection.doc(id).delete(); } catch (e) { print('Error deleting container: $e'); rethrow; } } /// Récupérer un container par ID Future getContainerById(String id) async { try { final doc = await _containersCollection.doc(id).get(); if (doc.exists) { return ContainerModel.fromMap(doc.data() as Map, doc.id); } return null; } catch (e) { print('Error getting container: $e'); rethrow; } } /// Récupérer tous les containers Stream> getContainers({ ContainerType? type, EquipmentStatus? status, String? searchQuery, }) { try { Query query = _containersCollection; // Filtre par type if (type != null) { query = query.where('type', isEqualTo: containerTypeToString(type)); } // Filtre par statut if (status != null) { query = query.where('status', isEqualTo: equipmentStatusToString(status)); } return query.snapshots().map((snapshot) { List containerList = snapshot.docs .map((doc) => ContainerModel.fromMap(doc.data() as Map, doc.id)) .toList(); // Filtre par recherche texte (côté client) if (searchQuery != null && searchQuery.isNotEmpty) { final lowerSearch = searchQuery.toLowerCase(); containerList = containerList.where((container) { return container.name.toLowerCase().contains(lowerSearch) || container.id.toLowerCase().contains(lowerSearch); }).toList(); } return containerList; }); } catch (e) { print('Error getting containers: $e'); rethrow; } } /// Ajouter un équipement à un container Future> addEquipmentToContainer({ required String containerId, required String equipmentId, String? userId, }) async { try { // Récupérer le container final container = await getContainerById(containerId); if (container == null) { return {'success': false, 'message': 'Container non trouvé'}; } // Vérifier si l'équipement n'est pas déjà dans ce container if (container.equipmentIds.contains(equipmentId)) { return {'success': false, 'message': 'Cet équipement est déjà dans ce container'}; } // Récupérer l'équipement pour vérifier s'il est déjà dans d'autres containers final equipmentDoc = await _equipmentCollection.doc(equipmentId).get(); if (!equipmentDoc.exists) { return {'success': false, 'message': 'Équipement non trouvé'}; } final equipment = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); // Avertir si l'équipement est déjà dans d'autres containers List otherContainers = []; if (equipment.parentBoxIds.isNotEmpty) { for (final boxId in equipment.parentBoxIds) { final box = await getContainerById(boxId); if (box != null) { otherContainers.add(box.name); } } } // Mettre à jour le container final updatedEquipmentIds = [...container.equipmentIds, equipmentId]; await updateContainer(containerId, { 'equipmentIds': updatedEquipmentIds, }); // Mettre à jour l'équipement final updatedParentBoxIds = [...equipment.parentBoxIds, containerId]; await _equipmentCollection.doc(equipmentId).update({ 'parentBoxIds': updatedParentBoxIds, 'updatedAt': Timestamp.fromDate(DateTime.now()), }); // Ajouter une entrée dans l'historique await _addHistoryEntry( containerId: containerId, action: 'equipment_added', equipmentId: equipmentId, newValue: equipmentId, userId: userId, ); return { 'success': true, 'message': 'Équipement ajouté avec succès', 'warnings': otherContainers.isNotEmpty ? 'Attention : cet équipement est également dans les containers suivants : ${otherContainers.join(", ")}' : null, }; } catch (e) { print('Error adding equipment to container: $e'); return {'success': false, 'message': 'Erreur: $e'}; } } /// Retirer un équipement d'un container Future removeEquipmentFromContainer({ required String containerId, required String equipmentId, String? userId, }) async { try { // Récupérer le container final container = await getContainerById(containerId); if (container == null) throw Exception('Container non trouvé'); // Mettre à jour le container final updatedEquipmentIds = container.equipmentIds.where((id) => id != equipmentId).toList(); await updateContainer(containerId, { 'equipmentIds': updatedEquipmentIds, }); // Mettre à jour l'équipement final equipmentDoc = await _equipmentCollection.doc(equipmentId).get(); if (equipmentDoc.exists) { final equipment = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); final updatedParentBoxIds = equipment.parentBoxIds.where((id) => id != containerId).toList(); await _equipmentCollection.doc(equipmentId).update({ 'parentBoxIds': updatedParentBoxIds, 'updatedAt': Timestamp.fromDate(DateTime.now()), }); } // Ajouter une entrée dans l'historique await _addHistoryEntry( containerId: containerId, action: 'equipment_removed', equipmentId: equipmentId, previousValue: equipmentId, userId: userId, ); } catch (e) { print('Error removing equipment from container: $e'); rethrow; } } /// Vérifier la disponibilité d'un container et de son contenu pour un événement Future> checkContainerAvailability({ required String containerId, required DateTime startDate, required DateTime endDate, String? excludeEventId, }) async { try { final container = await getContainerById(containerId); if (container == null) { return {'available': false, 'message': 'Container non trouvé'}; } // Vérifier le statut du container if (container.status != EquipmentStatus.available) { return { 'available': false, 'message': 'Container ${container.name} n\'est pas disponible (statut: ${container.status})', }; } // Vérifier la disponibilité de chaque équipement dans le container List unavailableEquipment = []; for (final equipmentId in container.equipmentIds) { final equipmentDoc = await _equipmentCollection.doc(equipmentId).get(); if (equipmentDoc.exists) { final equipment = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); if (equipment.status != EquipmentStatus.available) { unavailableEquipment.add('${equipment.name} (${equipment.status})'); } } } if (unavailableEquipment.isNotEmpty) { return { 'available': false, 'message': 'Certains équipements ne sont pas disponibles', 'unavailableItems': unavailableEquipment, }; } return {'available': true, 'message': 'Container et tout son contenu disponibles'}; } catch (e) { print('Error checking container availability: $e'); return {'available': false, 'message': 'Erreur: $e'}; } } /// Récupérer les équipements d'un container Future> getContainerEquipment(String containerId) async { try { final container = await getContainerById(containerId); if (container == null) return []; List equipment = []; for (final equipmentId in container.equipmentIds) { final doc = await _equipmentCollection.doc(equipmentId).get(); if (doc.exists) { equipment.add(EquipmentModel.fromMap(doc.data() as Map, doc.id)); } } return equipment; } catch (e) { print('Error getting container equipment: $e'); rethrow; } } /// Trouver tous les containers contenant un équipement spécifique Future> findContainersWithEquipment(String equipmentId) async { try { final snapshot = await _containersCollection .where('equipmentIds', arrayContains: equipmentId) .get(); return snapshot.docs .map((doc) => ContainerModel.fromMap(doc.data() as Map, doc.id)) .toList(); } catch (e) { print('Error finding containers with equipment: $e'); rethrow; } } /// Ajouter une entrée d'historique Future _addHistoryEntry({ required String containerId, required String action, String? equipmentId, String? previousValue, String? newValue, String? userId, }) async { try { final container = await getContainerById(containerId); if (container == null) return; final entry = ContainerHistoryEntry( timestamp: DateTime.now(), action: action, equipmentId: equipmentId, previousValue: previousValue, newValue: newValue, userId: userId, ); final updatedHistory = [...container.history, entry]; // Limiter l'historique aux 100 dernières entrées final limitedHistory = updatedHistory.length > 100 ? updatedHistory.sublist(updatedHistory.length - 100) : updatedHistory; await updateContainer(containerId, { 'history': limitedHistory.map((e) => e.toMap()).toList(), }); } catch (e) { print('Error adding history entry: $e'); // Ne pas throw pour éviter de bloquer l'opération principale } } /// Vérifier si un ID de container existe déjà Future checkContainerIdExists(String id) async { try { final doc = await _containersCollection.doc(id).get(); return doc.exists; } catch (e) { print('Error checking container ID: $e'); return false; } } }