import 'package:cloud_firestore/cloud_firestore.dart'; import '../data/models/group.dart'; import '../data/models/group_member.dart'; class GroupRepository { final FirebaseFirestore _firestore = FirebaseFirestore.instance; CollectionReference get _groupsCollection => _firestore.collection('groups'); CollectionReference _membersCollection(String groupId) { return _groupsCollection.doc(groupId).collection('members'); } Future createGroupWithMembers({ required Group group, required List members, }) async { try { return await _firestore.runTransaction((transaction) async { final groupRef = _groupsCollection.doc(); final groupData = group.toMap(); transaction.set(groupRef, groupData); for (var member in members) { final memberRef = groupRef.collection('members').doc(member.userId); transaction.set(memberRef, member.toMap()); } return groupRef.id; }); } catch (e) { throw Exception('Erreur lors de la création du groupe: $e'); } } Stream> getGroupsByUserId(String userId) { print('===== GroupRepository: getGroupsByUserId START ====='); print('UserId recherché: $userId'); return _groupsCollection .snapshots() .asyncMap((snapshot) async { print('===== GroupRepository: Nouveau snapshot (${DateTime.now()}) ====='); print('Nombre de documents: ${snapshot.docs.length}'); List userGroups = []; for (var groupDoc in snapshot.docs) { try { final groupId = groupDoc.id; print('--- Vérification groupe: $groupId ---'); // Vérifier si l'utilisateur est membre final memberDoc = await groupDoc.reference .collection('members') .doc(userId) .get(); print('Membre existe dans $groupId: ${memberDoc.exists}'); if (memberDoc.exists) { print('✓ Utilisateur trouvé dans $groupId'); final groupData = groupDoc.data() as Map; final group = Group.fromMap(groupData, groupId); final members = await getGroupMembers(groupId); print('${members.length} membres chargés pour $groupId'); userGroups.add(group.copyWith(members: members)); } else { print('✗ Utilisateur NON membre de $groupId'); } } catch (e, stackTrace) { print('ERREUR groupe ${groupDoc.id}: $e'); print('StackTrace: $stackTrace'); } } print('===== Retour: ${userGroups.length} groupes ====='); return userGroups; }) .distinct((prev, next) { // Comparer les listes pour éviter les doublons if (prev.length != next.length) { print('>>> Changement détecté: ${prev.length} -> ${next.length} groupes'); return false; } // Vérifier si les IDs sont identiques final prevIds = prev.map((g) => g.id).toSet(); final nextIds = next.map((g) => g.id).toSet(); final identical = prevIds.difference(nextIds).isEmpty && nextIds.difference(prevIds).isEmpty; if (!identical) { print('>>> Changement détecté: IDs différents'); } else { print('>>> Données identiques, émission ignorée'); } return identical; }) .handleError((error, stackTrace) { print('ERREUR stream: $error'); print('StackTrace: $stackTrace'); return []; }); } Future getGroupById(String groupId) async { try { final doc = await _groupsCollection.doc(groupId).get(); if (!doc.exists) return null; final group = Group.fromMap(doc.data() as Map, doc.id); final members = await getGroupMembers(groupId); return group.copyWith(members: members); } catch (e) { throw Exception('Erreur lors de la récupération du groupe: $e'); } } Future getGroupByTripId(String tripId) async { try { final querySnapshot = await _groupsCollection .where('tripId', isEqualTo: tripId) .limit(1) .get(); if (querySnapshot.docs.isEmpty) return null; final doc = querySnapshot.docs.first; final group = Group.fromMap(doc.data() as Map, doc.id); final members = await getGroupMembers(doc.id); return group.copyWith(members: members); } catch (e) { throw Exception('Erreur lors de la récupération du groupe: $e'); } } Future> getGroupMembers(String groupId) async { try { print('Chargement membres pour: $groupId'); final snapshot = await _membersCollection(groupId).get(); print('${snapshot.docs.length} membres trouvés'); return snapshot.docs .map((doc) { return GroupMember.fromMap( doc.data() as Map, doc.id, ); }) .toList(); } catch (e) { print('ERREUR getGroupMembers: $e'); throw Exception('Erreur lors de la récupération des membres: $e'); } } Future addMember(String groupId, GroupMember member) async { try { await _membersCollection(groupId).doc(member.userId).set(member.toMap()); await _groupsCollection.doc(groupId).update({ 'updatedAt': DateTime.now().millisecondsSinceEpoch, }); } catch (e) { throw Exception('Erreur lors de l\'ajout du membre: $e'); } } Future removeMember(String groupId, String userId) async { try { await _membersCollection(groupId).doc(userId).delete(); await _groupsCollection.doc(groupId).update({ 'updatedAt': DateTime.now().millisecondsSinceEpoch, }); } catch (e) { throw Exception('Erreur lors de la suppression du membre: $e'); } } Future updateGroup(String groupId, Group group) async { try { await _groupsCollection.doc(groupId).update( group.toMap()..['updatedAt'] = DateTime.now().millisecondsSinceEpoch, ); } catch (e) { throw Exception('Erreur lors de la mise à jour du groupe: $e'); } } Future deleteGroup(String groupId) async { try { final membersSnapshot = await _membersCollection(groupId).get(); for (var doc in membersSnapshot.docs) { await doc.reference.delete(); } await _groupsCollection.doc(groupId).delete(); } catch (e) { throw Exception('Erreur lors de la suppression du groupe: $e'); } } Stream> watchGroupMembers(String groupId) { return _membersCollection(groupId).snapshots().map( (snapshot) => snapshot.docs .map((doc) => GroupMember.fromMap( doc.data() as Map, doc.id, )) .toList(), ); } }