import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:file_picker/file_picker.dart'; import 'package:em2rp/models/event_model.dart'; import 'package:em2rp/models/event_type_model.dart'; import 'package:em2rp/models/user_model.dart'; import 'package:em2rp/services/event_form_service.dart'; import 'package:provider/provider.dart'; import 'package:em2rp/providers/event_provider.dart'; import 'package:em2rp/providers/local_user_provider.dart'; class EventFormController extends ChangeNotifier { // Controllers final TextEditingController nameController = TextEditingController(); final TextEditingController descriptionController = TextEditingController(); final TextEditingController basePriceController = TextEditingController(); final TextEditingController installationController = TextEditingController(); final TextEditingController disassemblyController = TextEditingController(); final TextEditingController addressController = TextEditingController(); // State variables DateTime? _startDateTime; DateTime? _endDateTime; bool _isLoading = false; String? _error; String? _success; String? _selectedEventTypeId; List _eventTypes = []; bool _isLoadingEventTypes = true; List _selectedUserIds = []; List _allUsers = []; bool _isLoadingUsers = true; List> _uploadedFiles = []; List> _selectedOptions = []; bool _formChanged = false; EventStatus _selectedStatus = EventStatus.waitingForApproval; // Getters DateTime? get startDateTime => _startDateTime; DateTime? get endDateTime => _endDateTime; bool get isLoading => _isLoading; String? get error => _error; String? get success => _success; String? get selectedEventTypeId => _selectedEventTypeId; List get eventTypes => _eventTypes; bool get isLoadingEventTypes => _isLoadingEventTypes; List get selectedUserIds => _selectedUserIds; List get allUsers => _allUsers; bool get isLoadingUsers => _isLoadingUsers; List> get uploadedFiles => _uploadedFiles; List> get selectedOptions => _selectedOptions; bool get formChanged => _formChanged; EventStatus get selectedStatus => _selectedStatus; EventFormController() { _setupListeners(); } void _setupListeners() { nameController.addListener(_onAnyFieldChanged); basePriceController.addListener(_onAnyFieldChanged); installationController.addListener(_onAnyFieldChanged); disassemblyController.addListener(_onAnyFieldChanged); addressController.addListener(_onAnyFieldChanged); descriptionController.addListener(_onAnyFieldChanged); } void _onAnyFieldChanged() { if (!_formChanged) { _formChanged = true; notifyListeners(); } } Future initialize([EventModel? existingEvent]) async { await Future.wait([ _fetchUsers(), _fetchEventTypes(), ]); if (existingEvent != null) { _populateFromEvent(existingEvent); } else { _selectedStatus = EventStatus.waitingForApproval; } notifyListeners(); } void _populateFromEvent(EventModel event) { nameController.text = event.name; descriptionController.text = event.description; basePriceController.text = event.basePrice.toStringAsFixed(2); installationController.text = event.installationTime.toString(); disassemblyController.text = event.disassemblyTime.toString(); addressController.text = event.address; _startDateTime = event.startDateTime; _endDateTime = event.endDateTime; _selectedEventTypeId = event.eventTypeId.isNotEmpty ? event.eventTypeId : null; _selectedUserIds = event.workforce.map((ref) => ref.id).toList(); _uploadedFiles = List>.from(event.documents); _selectedOptions = List>.from(event.options); _selectedStatus = event.status; } Future _fetchUsers() async { try { _allUsers = await EventFormService.fetchUsers(); _isLoadingUsers = false; } catch (e) { _error = e.toString(); _isLoadingUsers = false; } notifyListeners(); } Future _fetchEventTypes() async { try { _eventTypes = await EventFormService.fetchEventTypes(); _isLoadingEventTypes = false; } catch (e) { _error = e.toString(); _isLoadingEventTypes = false; } notifyListeners(); } void setStartDateTime(DateTime? dateTime) { _startDateTime = dateTime; if (_endDateTime != null && dateTime != null && (_endDateTime!.isBefore(dateTime) || _endDateTime!.isAtSameMomentAs(dateTime))) { _endDateTime = null; } _onAnyFieldChanged(); notifyListeners(); } void setEndDateTime(DateTime? dateTime) { _endDateTime = dateTime; _onAnyFieldChanged(); notifyListeners(); } void onEventTypeChanged(String? newTypeId, BuildContext context) { if (newTypeId == _selectedEventTypeId) return; final oldEventTypeIndex = _selectedEventTypeId != null ? _eventTypes.indexWhere((et) => et.id == _selectedEventTypeId) : -1; final EventType? oldEventType = oldEventTypeIndex != -1 ? _eventTypes[oldEventTypeIndex] : null; _selectedEventTypeId = newTypeId; if (newTypeId != null) { final selectedType = _eventTypes.firstWhere((et) => et.id == newTypeId); final defaultPrice = selectedType.defaultPrice; final currentPrice = double.tryParse(basePriceController.text.replaceAll(',', '.')); final oldDefaultPrice = oldEventType?.defaultPrice; if (basePriceController.text.isEmpty || (currentPrice != null && oldDefaultPrice != null && currentPrice == oldDefaultPrice)) { basePriceController.text = defaultPrice.toStringAsFixed(2); } final before = _selectedOptions.length; _selectedOptions.removeWhere((opt) { final types = opt['compatibleTypes'] as List?; if (types == null) return true; return !types.contains(selectedType.name); }); if (_selectedOptions.length < before) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Certaines options ont été retirées car non compatibles avec "${selectedType.name}".')), ); } } else { _selectedOptions.clear(); } _onAnyFieldChanged(); notifyListeners(); } void setSelectedUserIds(List userIds) { _selectedUserIds = userIds; _onAnyFieldChanged(); notifyListeners(); } void setUploadedFiles(List> files) { _uploadedFiles = files; _onAnyFieldChanged(); notifyListeners(); } void setSelectedOptions(List> options) { _selectedOptions = options; _onAnyFieldChanged(); notifyListeners(); } Future pickAndUploadFiles() async { final result = await FilePicker.platform.pickFiles(allowMultiple: true, withData: true); if (result != null && result.files.isNotEmpty) { _isLoading = true; _error = null; notifyListeners(); try { final files = await EventFormService.uploadFiles(result.files); _uploadedFiles.addAll(files); _onAnyFieldChanged(); } catch (e) { _error = 'Erreur lors de l\'upload : $e'; } finally { _isLoading = false; notifyListeners(); } } } bool validateForm() { return nameController.text.isNotEmpty && _startDateTime != null && _endDateTime != null && _selectedEventTypeId != null && addressController.text.isNotEmpty && (_endDateTime!.isAfter(_startDateTime!)); } Future submitForm(BuildContext context, {EventModel? existingEvent}) async { if (!validateForm()) { _error = "Veuillez remplir tous les champs obligatoires."; notifyListeners(); return false; } _isLoading = true; _error = null; _success = null; notifyListeners(); try { final eventTypeRef = _selectedEventTypeId != null ? FirebaseFirestore.instance.collection('eventTypes').doc(_selectedEventTypeId) : null; if (existingEvent != null) { // Mode édition // Gérer les nouveaux fichiers uploadés s'il y en a List> finalDocuments = List>.from(_uploadedFiles); // Identifier les nouveaux fichiers (ceux qui ont une URL temp) final newFiles = _uploadedFiles.where((file) => file['url']?.contains('events/temp/') ?? false).toList(); if (newFiles.isNotEmpty) { // Déplacer les nouveaux fichiers vers le dossier de l'événement final movedFiles = await EventFormService.moveFilesToEvent(newFiles, existingEvent.id); // Remplacer les URLs temporaires par les nouvelles URLs for (int i = 0; i < finalDocuments.length; i++) { final tempFile = finalDocuments[i]; final movedFile = movedFiles.firstWhere( (moved) => moved['name'] == tempFile['name'], orElse: () => tempFile, ); finalDocuments[i] = movedFile; } } final updatedEvent = EventModel( id: existingEvent.id, name: nameController.text.trim(), description: descriptionController.text.trim(), startDateTime: _startDateTime!, endDateTime: _endDateTime!, basePrice: double.tryParse(basePriceController.text.replaceAll(',', '.')) ?? 0.0, installationTime: int.tryParse(installationController.text) ?? 0, disassemblyTime: int.tryParse(disassemblyController.text) ?? 0, eventTypeId: _selectedEventTypeId!, eventTypeRef: eventTypeRef, customerId: existingEvent.customerId, address: addressController.text.trim(), workforce: _selectedUserIds .map((id) => FirebaseFirestore.instance.collection('users').doc(id)) .toList(), latitude: existingEvent.latitude, longitude: existingEvent.longitude, documents: finalDocuments, options: _selectedOptions, status: _selectedStatus, ); await EventFormService.updateEvent(updatedEvent); // Recharger les événements après modification final localUserProvider = Provider.of(context, listen: false); final eventProvider = Provider.of(context, listen: false); final userId = localUserProvider.uid; final canViewAllEvents = localUserProvider.hasPermission('view_all_events'); if (userId != null) { await eventProvider.loadUserEvents(userId, canViewAllEvents: canViewAllEvents); } _success = "Événement modifié avec succès !"; } else { // Mode création final newEvent = EventModel( id: '', name: nameController.text.trim(), description: descriptionController.text.trim(), startDateTime: _startDateTime!, endDateTime: _endDateTime!, basePrice: double.tryParse(basePriceController.text.replaceAll(',', '.')) ?? 0.0, installationTime: int.tryParse(installationController.text) ?? 0, disassemblyTime: int.tryParse(disassemblyController.text) ?? 0, eventTypeId: _selectedEventTypeId!, eventTypeRef: eventTypeRef, customerId: '', address: addressController.text.trim(), workforce: _selectedUserIds .map((id) => FirebaseFirestore.instance.collection('users').doc(id)) .toList(), latitude: 0.0, longitude: 0.0, documents: _uploadedFiles, options: _selectedOptions, status: _selectedStatus, ); final eventId = await EventFormService.createEvent(newEvent); final newFiles = await EventFormService.moveFilesToEvent(_uploadedFiles, eventId); await EventFormService.updateEventDocuments(eventId, newFiles); // Reload events final localUserProvider = Provider.of(context, listen: false); final eventProvider = Provider.of(context, listen: false); final userId = localUserProvider.uid; final canViewAllEvents = localUserProvider.hasPermission('view_all_events'); if (userId != null) { await eventProvider.loadUserEvents(userId, canViewAllEvents: canViewAllEvents); } _success = "Événement créé avec succès !"; } _formChanged = false; notifyListeners(); return true; } catch (e) { _error = "Erreur lors de la sauvegarde : $e"; notifyListeners(); return false; } finally { _isLoading = false; notifyListeners(); } } void clearError() { _error = null; notifyListeners(); } void clearSuccess() { _success = null; notifyListeners(); } @override void dispose() { nameController.dispose(); descriptionController.dispose(); basePriceController.dispose(); installationController.dispose(); disassemblyController.dispose(); addressController.dispose(); super.dispose(); } }