import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:em2rp/models/event_model.dart'; import 'package:em2rp/models/equipment_model.dart'; import 'package:em2rp/services/equipment_status_calculator.dart'; import 'package:em2rp/services/api_service.dart'; class EventPreparationService { final FirebaseFirestore _firestore = FirebaseFirestore.instance; final ApiService _apiService = apiService; // Collection references (utilisées uniquement pour les lectures) CollectionReference get _eventsCollection => _firestore.collection('events'); CollectionReference get _equipmentCollection => _firestore.collection('equipments'); // === PRÉPARATION === /// Valider un équipement individuel en préparation Future validateEquipmentPreparation(String eventId, String equipmentId) async { try { await _apiService.call('validateEquipmentPreparation', { 'eventId': eventId, 'equipmentId': equipmentId, }); } catch (e) { print('Error validating equipment preparation: $e'); rethrow; } } /// Valider tous les équipements en préparation Future validateAllPreparation(String eventId) async { try { await _apiService.call('validateAllPreparation', { 'eventId': eventId, }); // Invalider le cache des statuts d'équipement EquipmentStatusCalculator.invalidateGlobalCache(); } catch (e) { print('Error validating all preparation: $e'); rethrow; } } /// Finaliser la préparation avec des équipements manquants Future completePreparationWithMissing( String eventId, List missingEquipmentIds, ) async { try { final event = await _getEvent(eventId); if (event == null) { throw Exception('Event not found'); } // Marquer comme complété avec manquants await _eventsCollection.doc(eventId).update({ 'preparationStatus': preparationStatusToString(PreparationStatus.completedWithMissing), }); // Mettre à jour le statut des équipements préparés à "inUse" for (var equipment in event.assignedEquipment) { if (equipment.isPrepared && !missingEquipmentIds.contains(equipment.equipmentId)) { // Vérifier si l'équipement existe avant de mettre à jour son statut final doc = await _equipmentCollection.doc(equipment.equipmentId).get(); if (doc.exists) { await updateEquipmentStatus(equipment.equipmentId, EquipmentStatus.inUse); } } } } catch (e) { print('Error completing preparation with missing: $e'); rethrow; } } // === RETOUR === /// Valider le retour d'un équipement individuel Future validateEquipmentReturn( String eventId, String equipmentId, { int? returnedQuantity, }) async { try { await _apiService.call('validateEquipmentReturn', { 'eventId': eventId, 'equipmentId': equipmentId, if (returnedQuantity != null) 'returnedQuantity': returnedQuantity, }); } catch (e) { print('Error validating equipment return: $e'); rethrow; } } /// Valider tous les retours Future validateAllReturn( String eventId, [ Map? returnedQuantities, ]) async { try { await _apiService.call('validateAllReturn', { 'eventId': eventId, if (returnedQuantities != null) 'returnedQuantities': returnedQuantities, }); // Invalider le cache des statuts d'équipement EquipmentStatusCalculator.invalidateGlobalCache(); } catch (e) { print('Error validating all return: $e'); rethrow; } } /// Finaliser le retour avec des équipements manquants Future completeReturnWithMissing( String eventId, List missingEquipmentIds, ) async { try { final event = await _getEvent(eventId); if (event == null) { throw Exception('Event not found'); } // Marquer comme complété avec manquants await _eventsCollection.doc(eventId).update({ 'returnStatus': returnStatusToString(ReturnStatus.completedWithMissing), }); // Mettre à jour le statut des équipements retournés à "available" for (var equipment in event.assignedEquipment) { // Vérifier si le document existe final equipmentDoc = await _equipmentCollection.doc(equipment.equipmentId).get(); if (!equipmentDoc.exists) { continue; // Passer cet équipement s'il n'existe pas } final equipmentData = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); if (equipment.isReturned && !missingEquipmentIds.contains(equipment.equipmentId)) { // Mettre à jour le statut uniquement pour les équipements non quantifiables if (!equipmentData.hasQuantity) { await updateEquipmentStatus(equipment.equipmentId, EquipmentStatus.available); } // Restaurer le stock pour les consommables if (equipmentData.hasQuantity && equipment.returnedQuantity != null) { final currentAvailable = equipmentData.availableQuantity ?? 0; await _equipmentCollection.doc(equipment.equipmentId).update({ 'availableQuantity': currentAvailable + equipment.returnedQuantity!, 'updatedAt': Timestamp.fromDate(DateTime.now()), }); } } else if (missingEquipmentIds.contains(equipment.equipmentId)) { // Marquer comme perdu uniquement pour les équipements non quantifiables if (!equipmentData.hasQuantity) { await updateEquipmentStatus(equipment.equipmentId, EquipmentStatus.lost); } } } } catch (e) { print('Error completing return with missing: $e'); rethrow; } } // === HELPERS === /// Mettre à jour le statut d'un équipement Future updateEquipmentStatus(String equipmentId, EquipmentStatus status) async { try { // Vérifier que le document existe avant de le mettre à jour final doc = await _equipmentCollection.doc(equipmentId).get(); if (!doc.exists) { print('Warning: Equipment document $equipmentId does not exist, skipping status update'); return; } await _equipmentCollection.doc(equipmentId).update({ 'status': equipmentStatusToString(status), 'updatedAt': Timestamp.fromDate(DateTime.now()), }); } catch (e) { print('Error updating equipment status for $equipmentId: $e'); // Ne pas rethrow pour ne pas bloquer le processus si un équipement n'existe pas } } /// Récupérer un événement Future _getEvent(String eventId) async { try { final doc = await _eventsCollection.doc(eventId).get(); if (doc.exists) { return EventModel.fromMap(doc.data() as Map, doc.id); } return null; } catch (e) { print('Error getting event: $e'); rethrow; } } /// Ajouter un équipement à un événement Future addEquipmentToEvent( String eventId, String equipmentId, { int quantity = 1, }) async { try { final event = await _getEvent(eventId); if (event == null) { throw Exception('Event not found'); } // Vérifier que l'équipement n'est pas déjà ajouté final alreadyAdded = event.assignedEquipment.any((eq) => eq.equipmentId == equipmentId); if (alreadyAdded) { throw Exception('Equipment already added to event'); } final newEquipment = EventEquipment( equipmentId: equipmentId, quantity: quantity, ); final updatedEquipment = [...event.assignedEquipment, newEquipment]; await _eventsCollection.doc(eventId).update({ 'assignedEquipment': updatedEquipment.map((e) => e.toMap()).toList(), }); // Décrémenter le stock pour les consommables final equipmentDoc = await _equipmentCollection.doc(equipmentId).get(); if (equipmentDoc.exists) { final equipmentData = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); if (equipmentData.hasQuantity) { final currentAvailable = equipmentData.availableQuantity ?? 0; await _equipmentCollection.doc(equipmentId).update({ 'availableQuantity': currentAvailable - quantity, }); } } } catch (e) { print('Error adding equipment to event: $e'); rethrow; } } /// Retirer un équipement d'un événement Future removeEquipmentFromEvent(String eventId, String equipmentId) async { try { final event = await _getEvent(eventId); if (event == null) { throw Exception('Event not found'); } final equipmentToRemove = event.assignedEquipment.firstWhere( (eq) => eq.equipmentId == equipmentId, ); final updatedEquipment = event.assignedEquipment .where((eq) => eq.equipmentId != equipmentId) .toList(); await _eventsCollection.doc(eventId).update({ 'assignedEquipment': updatedEquipment.map((e) => e.toMap()).toList(), }); // Restaurer le stock pour les consommables final equipmentDoc = await _equipmentCollection.doc(equipmentId).get(); if (equipmentDoc.exists) { final equipmentData = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); if (equipmentData.hasQuantity) { final currentAvailable = equipmentData.availableQuantity ?? 0; await _equipmentCollection.doc(equipmentId).update({ 'availableQuantity': currentAvailable + equipmentToRemove.quantity, }); } } } catch (e) { print('Error removing equipment from event: $e'); rethrow; } } }