import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:travel_mate/services/error_service.dart';
import '../models/group.dart';
import '../models/group_member.dart';

class GroupRepository {
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;
  final _errorService = ErrorService();

  CollectionReference get _groupsCollection => _firestore.collection('groups');

  CollectionReference _membersCollection(String groupId) {
    return _groupsCollection.doc(groupId).collection('members');
  }

  Future<String> createGroupWithMembers({
    required Group group,
    required List<GroupMember> members,
  }) async {
    try {
      return await _firestore.runTransaction<String>((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<List<Group>> getGroupsByUserId(String userId) {    
    return _groupsCollection
        .snapshots()
        .asyncMap((snapshot) async {
          
          List<Group> userGroups = [];

          for (var groupDoc in snapshot.docs) {
            try {
              final groupId = groupDoc.id;
              
              // Vérifier si l'utilisateur est membre
              final memberDoc = await groupDoc.reference
                  .collection('members')
                  .doc(userId)
                  .get();

              if (memberDoc.exists) {
                final groupData = groupDoc.data() as Map<String, dynamic>;
                final group = Group.fromMap(groupData, groupId);
                
                final members = await getGroupMembers(groupId);
                userGroups.add(group.copyWith(members: members));
              } else {
                _errorService.logInfo('group_repository.dart','Utilisateur NON membre de $groupId');
              }
            } catch (e, stackTrace) {
              _errorService.logError(e.toString(), stackTrace);
            }
          }
          return userGroups;
        })
        .distinct((prev, next) {
          // Comparer les listes pour éviter les doublons
          if (prev.length != next.length) {
            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;
          
          return identical;
        })
        .handleError((error, stackTrace) {
          _errorService.logError(error, stackTrace);
          return <Group>[];
        });
  }

  Future<Group?> 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<String, dynamic>, 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<Group?> 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<String, dynamic>, 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<List<GroupMember>> getGroupMembers(String groupId) async {
    try {
      final snapshot = await _membersCollection(groupId).get();      
      return snapshot.docs
          .map((doc) {
            return GroupMember.fromMap(
              doc.data() as Map<String, dynamic>,
              doc.id,
            );
          })
          .toList();
    } catch (e) {
      throw Exception('Erreur lors de la récupération des membres: $e');
    }
  }

  Future<void> 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<void> 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<void> 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<void> deleteGroup(String tripId) async {
  try {
    final querySnapshot = await _groupsCollection
        .where('tripId', isEqualTo: tripId)
        .limit(1)
        .get();

    if (querySnapshot.docs.isEmpty) {
      throw Exception('Aucun groupe trouvé pour ce voyage');
    }

    final groupDoc = querySnapshot.docs.first;
    final groupId = groupDoc.id;

    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<List<GroupMember>> watchGroupMembers(String groupId) {
    return _membersCollection(groupId).snapshots().map(
          (snapshot) => snapshot.docs
              .map((doc) => GroupMember.fromMap(
                    doc.data() as Map<String, dynamic>,
                    doc.id,
                  ))
              .toList(),
        );
  }
}