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:em2rp/services/data_service.dart';
import 'package:em2rp/services/api_service.dart';
import 'package:provider/provider.dart';
import 'package:em2rp/providers/event_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();
  final TextEditingController jaugeController = TextEditingController();
  final TextEditingController contactEmailController = TextEditingController();
  final TextEditingController contactPhoneController = TextEditingController();

  // State variables
  DateTime? _startDateTime;
  DateTime? _endDateTime;
  bool _isLoading = false;
  String? _error;
  String? _success;
  String? _selectedEventTypeId;
  List<EventTypeModel> _eventTypes = [];
  bool _isLoadingEventTypes = true;
  List<String> _selectedUserIds = [];
  List<UserModel> _allUsers = [];
  bool _isLoadingUsers = true;
  List<Map<String, String>> _uploadedFiles = [];
  List<Map<String, dynamic>> _selectedOptions = [];
  bool _formChanged = false;
  EventStatus _selectedStatus = EventStatus.waitingForApproval;
  List<EventEquipment> _assignedEquipment = [];
  List<String> _assignedContainers = [];

  // 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<EventTypeModel> get eventTypes => _eventTypes;
  bool get isLoadingEventTypes => _isLoadingEventTypes;
  List<String> get selectedUserIds => _selectedUserIds;
  List<UserModel> get allUsers => _allUsers;
  bool get isLoadingUsers => _isLoadingUsers;
  List<Map<String, String>> get uploadedFiles => _uploadedFiles;
  List<Map<String, dynamic>> get selectedOptions => _selectedOptions;
  List<EventEquipment> get assignedEquipment => _assignedEquipment;
  List<String> get assignedContainers => _assignedContainers;
  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);
    jaugeController.addListener(_onAnyFieldChanged);
    contactEmailController.addListener(_onAnyFieldChanged);
    contactPhoneController.addListener(_onAnyFieldChanged);
  }

  void _onAnyFieldChanged() {
    if (!_formChanged) {
      _formChanged = true;
      notifyListeners();
    }
  }

  Future<void> initialize({EventModel? existingEvent, DateTime? selectedDate}) async {
    await Future.wait([
      _fetchUsers(),
      _fetchEventTypes(),
    ]);

    if (existingEvent != null) {
      // 🔧 FIX: Recharger l'événement avec tous les détails (équipements + containers avec enfants)
      try {
        final dataService = DataService(FirebaseFunctionsApiService());
        final result = await dataService.getEventWithDetails(existingEvent.id);
        final eventData = result['event'] as Map<String, dynamic>;

        // Reconstruire l'événement avec les données complètes
        final completeEvent = EventModel.fromMap(eventData, eventData['id'] as String);
        _populateFromEvent(completeEvent);
      } catch (e) {
        // Si erreur, utiliser l'événement existant (fallback)
        print('[EventFormController] Error loading event with details, using existing: $e');
        _populateFromEvent(existingEvent);
      }
    } else {
      _selectedStatus = EventStatus.waitingForApproval;

      // Préremplir les dates si une date est sélectionnée dans le calendrier
      if (selectedDate != null) {
        // Date de début : selectedDate à 20h00
        _startDateTime = DateTime(
          selectedDate.year,
          selectedDate.month,
          selectedDate.day,
          20,
          0,
        );
        // Date de fin : selectedDate + 4 heures
        _endDateTime = _startDateTime!.add(const Duration(hours: 4));
      }
    }
    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;
    jaugeController.text = event.jauge?.toString() ?? '';
    contactEmailController.text = event.contactEmail ?? '';
    contactPhoneController.text = event.contactPhone ?? '';
    _startDateTime = event.startDateTime;
    _endDateTime = event.endDateTime;
    _assignedEquipment = List<EventEquipment>.from(event.assignedEquipment);
    _assignedContainers = List<String>.from(event.assignedContainers);
    _selectedEventTypeId = event.eventTypeId.isNotEmpty ? event.eventTypeId : null;

    // Gérer workforce qui peut contenir String ou DocumentReference
    _selectedUserIds = event.workforce.map((ref) {
      if (ref is String) return ref;
      if (ref is DocumentReference) return ref.id;
      return '';
    }).where((id) => id.isNotEmpty).toList();

    _uploadedFiles = List<Map<String, String>>.from(event.documents);
    _selectedOptions = List<Map<String, dynamic>>.from(event.options);
    _selectedStatus = event.status;
  }

  Future<void> _fetchUsers() async {
    try {
      _allUsers = await EventFormService.fetchUsers();
      _isLoadingUsers = false;
    } catch (e) {
      _error = e.toString();
      _isLoadingUsers = false;
    }
    notifyListeners();
  }

  Future<void> _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 EventTypeModel? oldEventType = oldEventTypeIndex != -1 ? _eventTypes[oldEventTypeIndex] : null;

    _selectedEventTypeId = newTypeId;

    if (newTypeId != null) {
      final selectedType = _eventTypes.firstWhere((et) => et.id == newTypeId);

      // Utiliser le prix par défaut du type d'événement (prix TTC stocké dans basePrice)
      final defaultPriceTTC = selectedType.defaultPrice;
      final currentPrice = double.tryParse(basePriceController.text.replaceAll(',', '.'));
      final oldDefaultPrice = oldEventType?.defaultPrice;

      // Mettre à jour le prix TTC si le champ est vide ou si c'était l'ancien prix par défaut
      if (basePriceController.text.isEmpty ||
          (currentPrice != null && oldDefaultPrice != null && currentPrice == oldDefaultPrice)) {
        basePriceController.text = defaultPriceTTC.toStringAsFixed(2);
      }

      // Filtrer les options qui ne sont plus compatibles avec le nouveau type
      final before = _selectedOptions.length;
      _selectedOptions.removeWhere((opt) {
        // Vérifier si cette option est compatible avec le type d'événement sélectionné
        final optionEventTypes = opt['eventTypes'] as List<dynamic>? ?? [];
        return !optionEventTypes.contains(selectedType.id);
      });

      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<String> userIds) {
    _selectedUserIds = userIds;
    _onAnyFieldChanged();
    notifyListeners();
  }

  void setUploadedFiles(List<Map<String, String>> files) {
    _uploadedFiles = files;
    _onAnyFieldChanged();
    notifyListeners();
  }

  void setSelectedOptions(List<Map<String, dynamic>> options) {
    _selectedOptions = options;
    _onAnyFieldChanged();
    notifyListeners();
  }

  /// Ajoute ou met à jour l'option FRAIS_KM avec le prix calculé.
  /// L'option est au format attendu par Firestore : { id: "FRAIS_KM", price: <valeur> }
  void addTravelCostOption(double price) {
    // Retirer l'éventuelle option FRAIS_KM existante
    _selectedOptions.removeWhere((opt) => opt['id'] == 'FRAIS_KM');
    // Ajouter la nouvelle
    _selectedOptions.add({
      'id': 'FRAIS_KM',
      'price': double.parse(price.toStringAsFixed(2)),
    });
    _onAnyFieldChanged();
    notifyListeners();
  }

  void setAssignedEquipment(List<EventEquipment> equipment, List<String> containers) {
    _assignedEquipment = equipment;
    _assignedContainers = containers;
    _onAnyFieldChanged();
    notifyListeners();
  }

  Future<void> 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<bool> 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
          ? null  // Les références Firestore ne sont plus nécessaires, l'ID suffit
          : null;

      if (existingEvent != null) {
        // Mode édition
        // Gérer les nouveaux fichiers uploadés s'il y en a
        List<Map<String, String>> finalDocuments = List<Map<String, String>>.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(),
          // Envoyer directement les IDs au lieu de DocumentReference pour compatibilité Cloud Functions
          workforce: _selectedUserIds,
          latitude: existingEvent.latitude,
          longitude: existingEvent.longitude,
          documents: finalDocuments,
          options: _selectedOptions,
          status: _selectedStatus,
          jauge: jaugeController.text.isNotEmpty ? int.tryParse(jaugeController.text) : null,
          contactEmail: contactEmailController.text.isNotEmpty ? contactEmailController.text.trim() : null,
          contactPhone: contactPhoneController.text.isNotEmpty ? contactPhoneController.text.trim() : null,
          assignedEquipment: _assignedEquipment,
          assignedContainers: _assignedContainers,
          preparationStatus: existingEvent.preparationStatus,
          returnStatus: existingEvent.returnStatus,
        );

        await EventFormService.updateEvent(updatedEvent);

        // Mettre à jour l'événement dans le cache (au lieu de tout recharger)
        final eventProvider = Provider.of<EventProvider>(context, listen: false);
        await eventProvider.updateEvent(updatedEvent);

        _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(),
          // Envoyer directement les IDs au lieu de DocumentReference pour compatibilité Cloud Functions
          workforce: _selectedUserIds,
          latitude: 0.0,
          longitude: 0.0,
          documents: _uploadedFiles,
          options: _selectedOptions,
          status: _selectedStatus,
          jauge: jaugeController.text.isNotEmpty ? int.tryParse(jaugeController.text) : null,
          contactEmail: contactEmailController.text.isNotEmpty ? contactEmailController.text.trim() : null,
          contactPhone: contactPhoneController.text.isNotEmpty ? contactPhoneController.text.trim() : null,
          assignedContainers: _assignedContainers,
          assignedEquipment: _assignedEquipment,
        );

        final eventId = await EventFormService.createEvent(newEvent);

        // Créer l'événement avec l'ID retourné
        EventModel createdEvent = newEvent.copyWith(id: eventId);

        // Déplacer et mettre à jour les fichiers uniquement s'il y en a
        if (_uploadedFiles.isNotEmpty) {
          final newFiles = await EventFormService.moveFilesToEvent(_uploadedFiles, eventId);
          if (newFiles.isNotEmpty) {
            await EventFormService.updateEventDocuments(eventId, newFiles);
            // Mettre à jour l'événement avec les nouvelles URLs
            createdEvent = createdEvent.copyWith(documents: newFiles);
          }
        }

        // Ajouter l'événement au cache
        final eventProvider = Provider.of<EventProvider>(context, listen: false);
        await eventProvider.addEvent(createdEvent);

        _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();
    }
  }

  Future<bool> submitAsConfirmed(BuildContext context) async {
    _selectedStatus = EventStatus.confirmed;
    return await submitForm(context);
  }

  Future<bool> deleteEvent(BuildContext context, String eventId) async {
    _isLoading = true;
    _error = null;
    _success = null;
    notifyListeners();

    try {
      // Supprimer l'événement via le provider (qui appelle l'API et met à jour le cache)
      final eventProvider = Provider.of<EventProvider>(context, listen: false);
      await eventProvider.deleteEvent(eventId);

      _success = "Événement supprimé avec succès !";
      notifyListeners();
      return true;
    } catch (e) {
      _error = "Erreur lors de la suppression : $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();
    jaugeController.dispose();
    contactEmailController.dispose();
    contactPhoneController.dispose();
    super.dispose();
  }
}
