import 'package:em2rp/config/app_version.dart';
import 'package:em2rp/models/event_model.dart';
import 'package:intl/intl.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class IcsExportService {
  /// Génère un fichier ICS à partir d'un événement
  ///
  /// [eventTypeName] : Nom du type d'événement (optionnel, sera résolu si non fourni)
  /// [userNames] : Map des IDs utilisateurs vers leurs noms complets (optionnel)
  /// [optionNames] : Map des IDs options vers leurs noms (optionnel)
  static Future<String> generateIcsContent(
    EventModel event, {
    String? eventTypeName,
    Map<String, String>? userNames,
    Map<String, String>? optionNames,
  }) async {
    final now = DateTime.now().toUtc();
    final timestamp = '${DateFormat('yyyyMMddTHHmmss').format(now)}Z';

    // Récupérer les informations supplémentaires
    final resolvedEventTypeName = eventTypeName ?? await _getEventTypeName(event.eventTypeId);
    final workforce = await _getWorkforceDetails(event.workforce, userNames: userNames);
    final optionsWithNames = await _getOptionsDetails(event.options, optionNames: optionNames);

    // Formater les dates au format ICS (UTC)
    final startDate = _formatDateForIcs(event.startDateTime);
    final endDate = _formatDateForIcs(event.endDateTime);

    // Construire la description détaillée
    final description = _buildDescription(event, resolvedEventTypeName, workforce, optionsWithNames);

    // Générer un UID unique basé sur l'ID de l'événement
    final uid = 'em2rp-${event.id}@em2rp.app';

    // Construire le contenu ICS
    final icsContent = '''BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//EM2RP//Event Manager//FR
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
UID:$uid
DTSTAMP:$timestamp
DTSTART:$startDate
DTEND:$endDate
SUMMARY:${_escapeIcsText(event.name)}
DESCRIPTION:${_escapeIcsText(description)}
LOCATION:${_escapeIcsText(event.address)}
STATUS:${_getEventStatus(event.status)}
CATEGORIES:${_escapeIcsText(resolvedEventTypeName)}
END:VEVENT
END:VCALENDAR''';

    return icsContent;
  }

  /// Récupère le nom du type d'événement depuis EventModel (déjà chargé)
  /// Note: Les eventTypes sont maintenant chargés via Cloud Function dans l'EventModel
  static Future<String> _getEventTypeName(String eventTypeId) async {
    if (eventTypeId.isEmpty) return 'Non spécifié';

    // Les eventTypes sont publics et déjà chargés dans l'app via Cloud Function
    // On retourne simplement l'ID, le nom sera résolu par l'app
    return eventTypeId;
  }

  /// Récupère les détails de la main d'œuvre
  /// Si userNames est fourni, utilise les noms déjà résolus pour de meilleures performances
  static Future<List<String>> _getWorkforceDetails(
    List<dynamic> workforce, {
    Map<String, String>? userNames,
  }) async {
    final List<String> workforceNames = [];

    for (final ref in workforce) {
      try {
        // Si c'est déjà une Map avec les données, l'utiliser directement
        if (ref is Map<String, dynamic>) {
          final firstName = ref['firstName'] ?? '';
          final lastName = ref['lastName'] ?? '';
          if (firstName.isNotEmpty || lastName.isNotEmpty) {
            workforceNames.add('$firstName $lastName'.trim());
          }
          continue;
        }

        // Si c'est un String (UID) et qu'on a les noms résolus, les utiliser
        if (ref is String) {
          if (userNames != null && userNames.containsKey(ref)) {
            workforceNames.add(userNames[ref]!);
          } else {
            workforceNames.add('Utilisateur $ref');
          }
          continue;
        }

        // Si c'est une DocumentReference
        if (ref is DocumentReference) {
          final userId = ref.id;
          if (userNames != null && userNames.containsKey(userId)) {
            workforceNames.add(userNames[userId]!);
          } else {
            workforceNames.add('Utilisateur $userId');
          }
        }
      } catch (e) {
        print('Erreur lors du traitement des détails utilisateur: $e');
      }
    }

    return workforceNames;
  }

  /// Récupère les détails des options
  /// Si optionNames est fourni, utilise les noms déjà résolus
  static Future<List<Map<String, dynamic>>> _getOptionsDetails(
    List<Map<String, dynamic>> options, {
    Map<String, String>? optionNames,
  }) async {
    final List<Map<String, dynamic>> optionsWithNames = [];

    for (final option in options) {
      try {
        String optionName = option['name'] ?? 'Option inconnue';

        // Si on a l'ID de l'option et les noms résolus, utiliser le nom résolu
        final optionId = option['id'] ?? option['optionId'];
        if (optionId != null && optionNames != null && optionNames.containsKey(optionId)) {
          optionName = optionNames[optionId]!;
        } else if (optionName == 'Option inconnue' && optionId != null) {
          optionName = 'Option $optionId';
        }

        optionsWithNames.add({
          'name': optionName,
          'quantity': option['quantity'],
          'price': option['price'],
        });
      } catch (e) {
        print('Erreur lors du traitement des options: $e');
      }
    }

    return optionsWithNames;
  }

  /// Construit la description détaillée de l'événement
  static String _buildDescription(
    EventModel event,
    String eventTypeName,
    List<String> workforce,
    List<Map<String, dynamic>> optionsWithNames,
  ) {
    final buffer = StringBuffer();

    // Type d'événement
    buffer.writeln('TYPE: $eventTypeName');
    buffer.writeln('');

    // Description
    if (event.description.isNotEmpty) {
      buffer.writeln('DESCRIPTION:');
      buffer.writeln(event.description);
      buffer.writeln('');
    }

    // Jauge
    if (event.jauge != null) {
      buffer.writeln('JAUGE: ${event.jauge} personnes');
    }

    // Contact email
    if (event.contactEmail != null && event.contactEmail!.isNotEmpty) {
      buffer.writeln('EMAIL DE CONTACT: ${event.contactEmail}');
    }

    // Contact téléphone
    if (event.contactPhone != null && event.contactPhone!.isNotEmpty) {
      buffer.writeln('TÉLÉPHONE DE CONTACT: ${event.contactPhone}');
    }

    // Adresse
    if (event.address.isNotEmpty) {
      buffer.writeln('');
      buffer.writeln('ADRESSE: ${event.address}');
    }

    // Temps d'installation et démontage
    if (event.installationTime > 0 || event.disassemblyTime > 0) {
      buffer.writeln('');
      if (event.installationTime > 0) {
        buffer.writeln('INSTALLATION: ${event.installationTime}h');
      }
      if (event.disassemblyTime > 0) {
        buffer.writeln('DÉMONTAGE: ${event.disassemblyTime}h');
      }
    }

    // Main d'œuvre
    if (workforce.isNotEmpty) {
      buffer.writeln('');
      buffer.writeln('MAIN D\'ŒUVRE:');
      for (final name in workforce) {
        buffer.writeln('  - $name');
      }
    }

    // Options
    if (optionsWithNames.isNotEmpty) {
      buffer.writeln('');
      buffer.writeln('OPTIONS:');
      for (final option in optionsWithNames) {
        final optionName = option['name'] ?? 'Option inconnue';
        final quantity = option['quantity'];
        if (quantity != null && quantity > 1) {
          buffer.writeln('  - $optionName (x$quantity)');
        } else {
          buffer.writeln('  - $optionName');
        }
      }
    }

    // Prix
    if (event.basePrice > 0) {
      buffer.writeln('');
      buffer.writeln('PRIX DE BASE: ${event.basePrice.toStringAsFixed(2)}€');
    }

    // Lien vers l'application
    buffer.writeln('');
    buffer.writeln('---');
    buffer.writeln('Généré par EM2 Hub ${AppVersion.fullVersion} http://app.em2events.fr');

    return buffer.toString();
  }

  /// Formate une date au format ICS (yyyyMMddTHHmmssZ)
  static String _formatDateForIcs(DateTime dateTime) {
    final utcDate = dateTime.toUtc();
    return '${DateFormat('yyyyMMddTHHmmss').format(utcDate)}Z';
  }

  /// Échappe les caractères spéciaux pour le format ICS
  static String _escapeIcsText(String text) {
    return text
        .replaceAll('\\', '\\\\')
        .replaceAll(',', '\\,')
        .replaceAll(';', '\\;')
        .replaceAll('\n', '\\n')
        .replaceAll('\r', '');
  }

  /// Convertit le statut de l'événement en statut ICS
  static String _getEventStatus(EventStatus status) {
    switch (status) {
      case EventStatus.confirmed:
        return 'CONFIRMED';
      case EventStatus.canceled:
        return 'CANCELLED';
      case EventStatus.waitingForApproval:
        return 'TENTATIVE';
    }
  }

  /// Génère le nom du fichier ICS
  static String generateFileName(EventModel event) {
    final safeName = event.name
        .replaceAll(RegExp(r'[^\w\s-]'), '')
        .replaceAll(RegExp(r'\s+'), '_');
    final dateStr = DateFormat('yyyyMMdd').format(event.startDateTime);
    return 'event_${safeName}_$dateStr.ics';
  }
}

