import 'package:cloud_firestore/cloud_firestore.dart'; import '../models/activity.dart'; import '../services/error_service.dart'; /// Repository pour la gestion des activités dans Firestore class ActivityRepository { static final ActivityRepository _instance = ActivityRepository._internal(); factory ActivityRepository() => _instance; ActivityRepository._internal(); final FirebaseFirestore _firestore = FirebaseFirestore.instance; final ErrorService _errorService = ErrorService(); static const String _collection = 'activities'; /// Ajoute une nouvelle activité Future addActivity(Activity activity) async { try { print('ActivityRepository: Ajout d\'une activité: ${activity.name}'); final docRef = await _firestore.collection(_collection).add(activity.toMap()); // Mettre à jour l'activité avec l'ID généré await docRef.update({'id': docRef.id}); print('ActivityRepository: Activité ajoutée avec ID: ${docRef.id}'); return docRef.id; } catch (e) { print('ActivityRepository: Erreur lors de l\'ajout: $e'); _errorService.logError('activity_repository', 'Erreur ajout activité: $e'); return null; } } /// Récupère toutes les activités d'un voyage Future> getActivitiesByTrip(String tripId) async { try { print('ActivityRepository: Récupération des activités pour le voyage: $tripId'); final querySnapshot = await _firestore .collection(_collection) .where('tripId', isEqualTo: tripId) .orderBy('updatedAt', descending: true) .get(); final activities = querySnapshot.docs .map((doc) => Activity.fromSnapshot(doc)) .toList(); print('ActivityRepository: ${activities.length} activités trouvées'); return activities; } catch (e) { print('ActivityRepository: Erreur lors de la récupération: $e'); _errorService.logError('activity_repository', 'Erreur récupération activités: $e'); return []; } } /// Récupère une activité par son ID Future getActivityById(String activityId) async { try { final doc = await _firestore.collection(_collection).doc(activityId).get(); if (doc.exists) { return Activity.fromSnapshot(doc); } return null; } catch (e) { print('ActivityRepository: Erreur récupération activité: $e'); _errorService.logError('activity_repository', 'Erreur récupération activité: $e'); return null; } } /// Met à jour une activité Future updateActivity(Activity activity) async { try { print('ActivityRepository: Mise à jour de l\'activité: ${activity.id}'); await _firestore .collection(_collection) .doc(activity.id) .update(activity.copyWith(updatedAt: DateTime.now()).toMap()); print('ActivityRepository: Activité mise à jour avec succès'); return true; } catch (e) { print('ActivityRepository: Erreur lors de la mise à jour: $e'); _errorService.logError('activity_repository', 'Erreur mise à jour activité: $e'); return false; } } /// Supprime une activité Future deleteActivity(String activityId) async { try { print('ActivityRepository: Suppression de l\'activité: $activityId'); await _firestore.collection(_collection).doc(activityId).delete(); print('ActivityRepository: Activité supprimée avec succès'); return true; } catch (e) { print('ActivityRepository: Erreur lors de la suppression: $e'); _errorService.logError('activity_repository', 'Erreur suppression activité: $e'); return false; } } /// Vote pour une activité Future voteForActivity(String activityId, String userId, int vote) async { try { print('ActivityRepository: Vote pour l\'activité $activityId: $vote'); // vote: 1 pour positif, -1 pour négatif, 0 pour supprimer le vote final activityRef = _firestore.collection(_collection).doc(activityId); await _firestore.runTransaction((transaction) async { final snapshot = await transaction.get(activityRef); if (!snapshot.exists) { throw Exception('Activité non trouvée'); } final activity = Activity.fromSnapshot(snapshot); final newVotes = Map.from(activity.votes); if (vote == 0) { // Supprimer le vote newVotes.remove(userId); } else { // Ajouter ou modifier le vote newVotes[userId] = vote; } transaction.update(activityRef, { 'votes': newVotes, 'updatedAt': Timestamp.fromDate(DateTime.now()), }); }); print('ActivityRepository: Vote enregistré avec succès'); return true; } catch (e) { print('ActivityRepository: Erreur lors du vote: $e'); _errorService.logError('activity_repository', 'Erreur vote: $e'); return false; } } /// Récupère les activités avec un stream pour les mises à jour en temps réel Stream> getActivitiesStream(String tripId) { try { return _firestore .collection(_collection) .where('tripId', isEqualTo: tripId) .orderBy('updatedAt', descending: true) .snapshots() .map((snapshot) { return snapshot.docs .map((doc) => Activity.fromSnapshot(doc)) .toList(); }); } catch (e) { print('ActivityRepository: Erreur stream activités: $e'); _errorService.logError('activity_repository', 'Erreur stream activités: $e'); return Stream.value([]); } } /// Ajoute plusieurs activités en lot Future> addActivitiesBatch(List activities) async { try { print('ActivityRepository: Ajout en lot de ${activities.length} activités'); final batch = _firestore.batch(); final addedIds = []; for (final activity in activities) { final docRef = _firestore.collection(_collection).doc(); final activityWithId = activity.copyWith(id: docRef.id); batch.set(docRef, activityWithId.toMap()); addedIds.add(docRef.id); } await batch.commit(); print('ActivityRepository: ${addedIds.length} activités ajoutées en lot'); return addedIds; } catch (e) { print('ActivityRepository: Erreur ajout en lot: $e'); _errorService.logError('activity_repository', 'Erreur ajout en lot: $e'); return []; } } /// Recherche des activités par catégorie Future> getActivitiesByCategory(String tripId, String category) async { try { final querySnapshot = await _firestore .collection(_collection) .where('tripId', isEqualTo: tripId) .where('category', isEqualTo: category) .orderBy('updatedAt', descending: true) .get(); return querySnapshot.docs .map((doc) => Activity.fromSnapshot(doc)) .toList(); } catch (e) { print('ActivityRepository: Erreur recherche par catégorie: $e'); _errorService.logError('activity_repository', 'Erreur recherche par catégorie: $e'); return []; } } /// Récupère les activités les mieux notées d'un voyage Future> getTopRatedActivities(String tripId, {int limit = 10}) async { try { final activities = await getActivitiesByTrip(tripId); // Trier par nombre de votes positifs puis par note Google activities.sort((a, b) { final aScore = a.totalVotes; final bScore = b.totalVotes; if (aScore != bScore) { return bScore.compareTo(aScore); } return (b.rating ?? 0).compareTo(a.rating ?? 0); }); return activities.take(limit).toList(); } catch (e) { print('ActivityRepository: Erreur activités top rated: $e'); _errorService.logError('activity_repository', 'Erreur top rated: $e'); return []; } } /// Vérifie si une activité existe déjà pour un voyage (basé sur placeId) Future findExistingActivity(String tripId, String placeId) async { try { final querySnapshot = await _firestore .collection(_collection) .where('tripId', isEqualTo: tripId) .where('placeId', isEqualTo: placeId) .limit(1) .get(); if (querySnapshot.docs.isNotEmpty) { return Activity.fromSnapshot(querySnapshot.docs.first); } return null; } catch (e) { print('ActivityRepository: Erreur recherche activité existante: $e'); return null; } } }