/// A service that handles trip-related business logic and data operations.
///
/// This service provides functionality for:
/// - Trip creation, updating, and deletion
/// - Trip validation and business rule enforcement
/// - Location-based trip suggestions
/// - Trip statistics and analytics
/// - Integration with Firebase Firestore for data persistence
///
/// The service ensures data integrity by validating trip information
/// before database operations and provides comprehensive error handling
/// and logging through the ErrorService.
///
/// Example usage:
/// ```dart
/// final tripService = TripService();
/// 
/// // Create a new trip
/// final tripId = await tripService.createTrip(newTrip);
/// 
/// // Get trip suggestions for a location
/// final suggestions = await tripService.getTripSuggestions('Paris');
/// 
/// // Calculate trip statistics
/// final stats = await tripService.getTripStatistics(tripId);
/// ```
library;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:travel_mate/services/error_service.dart';
import '../models/trip.dart';

/// Service for managing trip-related operations and business logic.
class TripService {
  /// Service for error handling and logging
  final _errorService = ErrorService();
  
  /// Firestore instance for database operations
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;
  
  /// Collection name for trips in Firestore
  static const String _tripsCollection = 'trips';

  // Charger tous les voyages
  Future<List<Trip>> loadTrips() async {
    try {
      final QuerySnapshot querySnapshot = await _firestore
          .collection(_tripsCollection)
          .orderBy('createdAt', descending: true)
          .get();

      return querySnapshot.docs.map((doc) {
        final data = doc.data() as Map<String, dynamic>;
        return Trip.fromMap({...data, 'id': doc.id}, doc.id);
      }).toList();
    } catch (e) {
      _errorService.logError('Erreur lors du chargement des voyages: $e', StackTrace.current);
      return [];
    }
  }

  // Ajouter un nouveau voyage
  Future<bool> addTrip(Trip trip) async {
    try {
      final tripData = trip.toMap();
      // Retirer l'ID vide du map
      tripData.remove('id');
      
      // Convertir les dates en Timestamp pour Firestore
      tripData['startDate'] = Timestamp.fromDate(trip.startDate);
      tripData['endDate'] = Timestamp.fromDate(trip.endDate);
      tripData['createdAt'] = FieldValue.serverTimestamp();
      tripData['updatedAt'] = FieldValue.serverTimestamp();
      
      await _firestore.collection(_tripsCollection).add(tripData);
      return true;
    } catch (e) {
      _errorService.logError('Erreur lors de l\'ajout du voyage: $e', StackTrace.current);
      return false;
    }
  }

  // Stream pour écouter les voyages d'un utilisateur en temps réel
  Stream<List<Trip>> getTripsStreamByUser(String userId, String userEmail) {
    return _firestore
        .collection(_tripsCollection)
        .snapshots()
        .map((snapshot) {
      
      final List<Trip> trips = [];
      
      for (int i = 0; i < snapshot.docs.length; i++) {
        var doc = snapshot.docs[i];
        
        try {
          final data = doc.data();
          
          // Vérifier si l'utilisateur est impliqué dans ce voyage
          final String createdBy = data['createdBy']?.toString() ?? '';
          final List<dynamic> participants = data['participants'] ?? [];
          
          bool userIsInvolved = false;
          String reason = '';
          
          // L'utilisateur est le créateur
          if (createdBy == userId) {
            userIsInvolved = true;
            reason = 'Créateur du voyage';
          }
          
          // L'utilisateur est dans la liste des participants (par ID uniquement)
          if (participants.contains(userId)) {
            userIsInvolved = true;
            reason = reason.isEmpty ? 'Participant par ID' : '$reason + Participant par ID';
          }
          
          if (userIsInvolved) {
            final trip = _convertDocumentToTrip(doc.id, data);
            if (trip != null) {
              trips.add(trip);
            }
          }
        } catch (e, stackTrace) {
          _errorService.logError('Erreur lors du traitement du document ${doc.id}: $e', stackTrace);
        }
      }
      
      // Trier par date de création (les plus récents en premier)
      trips.sort((a, b) {
        try {
          return b.createdAt.compareTo(a.createdAt);
        } catch (e) {
          _errorService.logError('Erreur lors du tri: $e', StackTrace.current);
          return 0;
        }
      });
      
      return trips;
    }).handleError((error, stackTrace) {
      _errorService.logError('Erreur dans le stream: $error', stackTrace);
      return <Trip>[];
    });
  }

  // Obtenir les voyages d'un utilisateur (version simplifiée)
  Future<List<Trip>> getTripsByUser(String userId) async {
    try {
      // Récupérer d'abord les voyages créés par l'utilisateur
      final QuerySnapshot createdTrips = await _firestore
          .collection(_tripsCollection)
          .where('createdBy', isEqualTo: userId)
          .get();

      final List<Trip> trips = [];
      
      for (var doc in createdTrips.docs) {
        try {
          final data = doc.data() as Map<String, dynamic>;
          final trip = _convertDocumentToTrip(doc.id, data);
          if (trip != null) {
            trips.add(trip);
          }
        } catch (e) {
          _errorService.logError('Erreur lors de la conversion du voyage créé ${doc.id}: $e', StackTrace.current);
        }
      }

      // Trier par date de création
      trips.sort((a, b) {
        try {
          return b.createdAt.compareTo(a.createdAt);
        } catch (e) {
          return 0;
        }
      });
      return trips;
    } catch (e) {
      _errorService.logError('Erreur lors de la récupération des voyages: $e', StackTrace.current);
      return [];
    }
  }

  // Méthode helper pour convertir un document Firestore en Trip
  Trip? _convertDocumentToTrip(String docId, Map<String, dynamic> data) {    
    try {
      // Créer une copie des données pour ne pas modifier l'original
      Map<String, dynamic> processedData = Map<String, dynamic>.from(data);
      
      // Convertir les Timestamps Firestore en String ISO
      if (processedData['createdAt'] is Timestamp) {
        processedData['createdAt'] = (processedData['createdAt'] as Timestamp).toDate().toIso8601String();
      }
      
      if (processedData['updatedAt'] is Timestamp) {
        processedData['updatedAt'] = (processedData['updatedAt'] as Timestamp).toDate().toIso8601String();
      }
      
      if (processedData['startDate'] is Timestamp) {
        processedData['startDate'] = (processedData['startDate'] as Timestamp).toDate().toIso8601String();
      }
      
      if (processedData['endDate'] is Timestamp) {
        processedData['endDate'] = (processedData['endDate'] as Timestamp).toDate().toIso8601String();
      }

      // Assurer que tous les champs requis sont présents
      processedData['id'] = docId;
      processedData['participants'] = processedData['participants'] ?? [];
      processedData['budget'] = (processedData['budget'] is num) ? (processedData['budget'] as num).toDouble() : 0.0;
      processedData['description'] = processedData['description'] ?? '';
      processedData['status'] = processedData['status'] ?? 'draft';
      
      final trip = Trip.fromMap(processedData, docId);
      return trip;
      
    } catch (e, stackTrace) {
      _errorService.logError('Erreur lors de la conversion du document $docId: $e', stackTrace);
      return null;
    }
  }

  // Mettre à jour un voyage
  Future<bool> updateTrip(Trip updatedTrip) async {
    try {
      final tripData = updatedTrip.toMap();
      tripData['updatedAt'] = FieldValue.serverTimestamp();
      tripData.remove('id'); // Retirer l'ID des données à mettre à jour

      await _firestore
          .collection(_tripsCollection)
          .doc(updatedTrip.id)
          .update(tripData);
      return true;
    } catch (e) {
      _errorService.logError('Erreur lors de la mise à jour du voyage: $e', StackTrace.current);
      return false;
    }
  }

  // Supprimer un voyage
  Future<bool> deleteTrip(String tripId) async {
    try {
      await _firestore.collection(_tripsCollection).doc(tripId).delete();
      return true;
    } catch (e) {
      _errorService.logError('Erreur lors de la suppression du voyage: $e', StackTrace.current);
      return false;
    }
  }

  // Obtenir un voyage par son ID
  Future<Trip?> getTripById(String tripId) async {
    try {
      final DocumentSnapshot doc = await _firestore
          .collection(_tripsCollection)
          .doc(tripId)
          .get();

      if (doc.exists) {
        final data = doc.data() as Map<String, dynamic>;
        return Trip.fromMap({...data, 'id': doc.id}, doc.id);
      }
      return null;
    } catch (e) {
      _errorService.logError('Erreur lors de la récupération du voyage: $e', StackTrace.current);
      return null;
    }
  }

  // Ajouter un participant à un voyage
  Future<bool> addParticipant(String tripId, String userId) async {
    try {
      await _firestore.collection(_tripsCollection).doc(tripId).update({
        'participants': FieldValue.arrayUnion([userId]),
        'updatedAt': FieldValue.serverTimestamp(),
      });
      return true;
    } catch (e) {
      _errorService.logError('Erreur lors de l\'ajout du participant: $e', StackTrace.current);
      return false;
    }
  }

  // Retirer un participant d'un voyage
  Future<bool> removeParticipant(String tripId, String userId) async {
    try {
      await _firestore.collection(_tripsCollection).doc(tripId).update({
        'participants': FieldValue.arrayRemove([userId]),
        'updatedAt': FieldValue.serverTimestamp(),
      });
      return true;
    } catch (e) {
      _errorService.logError('Erreur lors du retrait du participant: $e', StackTrace.current);
      return false;
    }
  }
}