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_service.dart'; class EventPreparationService { final FirebaseFirestore _firestore = FirebaseFirestore.instance; final EquipmentService _equipmentService = EquipmentService(); // Collection references CollectionReference get _eventsCollection => _firestore.collection('events'); CollectionReference get _equipmentCollection => _firestore.collection('equipment'); // === PRÉPARATION === /// Valider un équipement individuel en préparation Future validateEquipmentPreparation(String eventId, String equipmentId) async { try { final event = await _getEvent(eventId); if (event == null) { throw Exception('Event not found'); } // Mettre à jour le statut de l'équipement dans la liste final updatedEquipment = event.assignedEquipment.map((eq) { if (eq.equipmentId == equipmentId) { return eq.copyWith(isPrepared: true); } return eq; }).toList(); await _eventsCollection.doc(eventId).update({ 'assignedEquipment': updatedEquipment.map((e) => e.toMap()).toList(), }); } catch (e) { print('Error validating equipment preparation: $e'); rethrow; } } /// Valider tous les équipements en préparation Future validateAllPreparation(String eventId) async { try { final event = await _getEvent(eventId); if (event == null) { throw Exception('Event not found'); } // Marquer tous les équipements comme préparés final updatedEquipment = event.assignedEquipment.map((eq) { return eq.copyWith(isPrepared: true); }).toList(); await _eventsCollection.doc(eventId).update({ 'assignedEquipment': updatedEquipment.map((e) => e.toMap()).toList(), 'preparationStatus': preparationStatusToString(PreparationStatus.completed), }); // Mettre à jour le statut des équipements à "inUse" for (var equipment in event.assignedEquipment) { await updateEquipmentStatus(equipment.equipmentId, EquipmentStatus.inUse); } } 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)) { 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 { final event = await _getEvent(eventId); if (event == null) { throw Exception('Event not found'); } // Mettre à jour le statut de l'équipement dans la liste final updatedEquipment = event.assignedEquipment.map((eq) { if (eq.equipmentId == equipmentId) { return eq.copyWith( isReturned: true, returnedQuantity: returnedQuantity, ); } return eq; }).toList(); await _eventsCollection.doc(eventId).update({ 'assignedEquipment': updatedEquipment.map((e) => e.toMap()).toList(), }); // Mettre à jour le stock si c'est un consommable if (returnedQuantity != null) { final equipmentDoc = await _equipmentCollection.doc(equipmentId).get(); if (equipmentDoc.exists) { final equipment = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); if (equipment.hasQuantity) { final currentAvailable = equipment.availableQuantity ?? 0; await _equipmentCollection.doc(equipmentId).update({ 'availableQuantity': currentAvailable + returnedQuantity, }); } } } } catch (e) { print('Error validating equipment return: $e'); rethrow; } } /// Valider tous les retours Future validateAllReturn(String eventId) async { try { final event = await _getEvent(eventId); if (event == null) { throw Exception('Event not found'); } // Marquer tous les équipements comme retournés final updatedEquipment = event.assignedEquipment.map((eq) { return eq.copyWith( isReturned: true, returnedQuantity: eq.returnedQuantity ?? eq.quantity, ); }).toList(); await _eventsCollection.doc(eventId).update({ 'assignedEquipment': updatedEquipment.map((e) => e.toMap()).toList(), 'returnStatus': returnStatusToString(ReturnStatus.completed), }); // Mettre à jour le statut des équipements à "available" et gérer les stocks for (var equipment in updatedEquipment) { await updateEquipmentStatus(equipment.equipmentId, EquipmentStatus.available); // Restaurer le stock pour les consommables final equipmentDoc = await _equipmentCollection.doc(equipment.equipmentId).get(); if (equipmentDoc.exists) { final equipmentData = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); if (equipmentData.hasQuantity && equipment.returnedQuantity != null) { final currentAvailable = equipmentData.availableQuantity ?? 0; await _equipmentCollection.doc(equipment.equipmentId).update({ 'availableQuantity': currentAvailable + equipment.returnedQuantity!, }); } } } } 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) { if (equipment.isReturned && !missingEquipmentIds.contains(equipment.equipmentId)) { await updateEquipmentStatus(equipment.equipmentId, EquipmentStatus.available); // Restaurer le stock pour les consommables final equipmentDoc = await _equipmentCollection.doc(equipment.equipmentId).get(); if (equipmentDoc.exists) { final equipmentData = EquipmentModel.fromMap( equipmentDoc.data() as Map, equipmentDoc.id, ); if (equipmentData.hasQuantity && equipment.returnedQuantity != null) { final currentAvailable = equipmentData.availableQuantity ?? 0; await _equipmentCollection.doc(equipment.equipmentId).update({ 'availableQuantity': currentAvailable + equipment.returnedQuantity!, }); } } } else if (missingEquipmentIds.contains(equipment.equipmentId)) { // Marquer comme perdu 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 { await _equipmentCollection.doc(equipmentId).update({ 'status': equipmentStatusToString(status), 'updatedAt': Timestamp.fromDate(DateTime.now()), }); } catch (e) { print('Error updating equipment status: $e'); rethrow; } } /// 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; } } }