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

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

  CollectionReference get _accountCollection =>
      _firestore.collection('accounts');

  CollectionReference _membersCollection(String accountId) {
    return _accountCollection.doc(accountId).collection('members');
  }

  Future<String> createAccountWithMembers({
    required Account account,
    required List<GroupMember> members,
  }) async {
    try {
      return await _firestore.runTransaction<String>((transaction) async {
        final accountRef = _accountCollection.doc();

        final accountData = account.toMap();

        transaction.set(accountRef, accountData);

        for (var member in members) {
          final memberRef = accountRef.collection('members').doc(member.userId);
          transaction.set(memberRef, member.toMap());
        }

        return accountRef.id;
      });
    } catch (e, stackTrace) {
      _errorService.logError(
        'account_repository.dart',
        'Erreur lors de la création du compte: $e',
        stackTrace,
      );
      throw Exception('Impossible de créer le compte');
    }
  }

  Stream<List<Account>> getAccountByUserId(String userId) {
    return _accountCollection
        .snapshots()
        .asyncMap((snapshot) async {
          List<Account> userAccounts = [];

          for (var accountDoc in snapshot.docs) {
            try {
              final accountId = accountDoc.id;

              final memberDoc = await accountDoc.reference
                  .collection('members')
                  .doc(userId)
                  .get();
              if (memberDoc.exists) {
                final accountData = accountDoc.data() as Map<String, dynamic>;
                final account = Account.fromMap(
                  accountData,
                  accountId,
                ); // ✅ Ajout de l'ID
                final members = await getAccountMembers(accountId);
                userAccounts.add(account.copyWith(members: members));
              } else {
                _errorService.logInfo(
                  'account_repository.dart',
                  'Utilisateur NON membre de $accountId',
                );
              }
            } catch (e, stackTrace) {
              _errorService.logError(
                'account_repository.dart',
                'Erreur processing account doc: $e',
                stackTrace,
              );
            }
          }
          return userAccounts;
        })
        .distinct((prev, next) {
          if (prev.length != next.length) return false;
          final prevIds = prev.map((a) => a.id).toSet();
          final nextIds = next.map((a) => a.id).toSet();

          final identical =
              prevIds.difference(nextIds).isEmpty &&
              nextIds.difference(prevIds).isEmpty;

          return identical;
        })
        .handleError((error, stackTrace) {
          _errorService.logError(
            'account_repository.dart',
            'Erreur stream accounts: $error',
            stackTrace,
          );
          return <Account>[];
        });
  }

  Future<List<GroupMember>> getAccountMembers(String accountId) async {
    try {
      final snapshot = await _membersCollection(accountId).get();
      return snapshot.docs.map((doc) {
        return GroupMember.fromMap(doc.data() as Map<String, dynamic>, doc.id);
      }).toList();
    } catch (e, stackTrace) {
      _errorService.logError(
        'account_repository.dart',
        'Erreur lors de la récupération des membres: $e',
        stackTrace,
      );
      throw Exception('Impossible de récupérer les membres');
    }
  }

  Future<Account?> getAccountById(String accountId) async {
    try {
      final doc = await _firestore.collection('accounts').doc(accountId).get();
      if (doc.exists) {
        return Account.fromMap(doc.data() as Map<String, dynamic>, doc.id);
      }
      return null;
    } catch (e, stackTrace) {
      _errorService.logError(
        'account_repository.dart',
        'Erreur lors de la récupération du compte: $e',
        stackTrace,
      );
      throw Exception('Impossible de récupérer le compte');
    }
  }

  Future<Account?> getAccountByTripId(String tripId) async {
    try {
      final querySnapshot = await _firestore
          .collection('accounts')
          .where('tripId', isEqualTo: tripId)
          .limit(1)
          .get();

      if (querySnapshot.docs.isNotEmpty) {
        final doc = querySnapshot.docs.first;
        return Account.fromMap(doc.data(), doc.id);
      }
      return null;
    } catch (e, stackTrace) {
      _errorService.logError(
        'account_repository.dart',
        'Erreur lors de la récupération du compte: $e',
        stackTrace,
      );
      throw Exception('Impossible de récupérer le compte');
    }
  }

  Future<void> updateAccount(String accountId, Account account) async {
    try {
      // Mettre à jour la date de modification
      final updatedAccount = account.copyWith(updatedAt: DateTime.now());
      await _firestore
          .collection('accounts')
          .doc(accountId)
          .update(updatedAccount.toMap());
    } catch (e, stackTrace) {
      _errorService.logError(
        'account_repository.dart',
        'Erreur lors de la mise à jour du compte: $e',
        stackTrace,
      );
      throw Exception('Impossible de mettre à jour le compte');
    }
  }

  Future<void> deleteAccount(String tripId) async {
    try {
      final querySnapshot = await _firestore
          .collection('accounts')
          .where('tripId', isEqualTo: tripId)
          .get();
      if (querySnapshot.docs.isEmpty) {
        throw Exception('Aucun compte trouvé pour ce voyage');
      }

      final docId = querySnapshot.docs.first.id;

      // Supprimer tous les membres
      final membersSnapshot = await _membersCollection(docId).get();
      for (var memberDoc in membersSnapshot.docs) {
        await _membersCollection(docId).doc(memberDoc.id).delete();
      }

      // Supprimer le compte
      await _accountCollection.doc(docId).delete();
    } catch (e, stackTrace) {
      _errorService.logError(
        'account_repository.dart',
        'Erreur lors de la suppression du compte: $e',
        stackTrace,
      );
      throw Exception('Impossible de supprimer le compte');
    }
  }

  Stream<List<GroupMember>> watchGroupMembers(String accountId) {
    return _membersCollection(accountId).snapshots().map(
      (snapshot) => snapshot.docs
          .map(
            (doc) =>
                GroupMember.fromMap(doc.data() as Map<String, dynamic>, doc.id),
          )
          .toList(),
    );
  }

  Stream<Account?> watchAccount(String accountId) {
    return _accountCollection.doc(accountId).snapshots().map((doc) {
      if (doc.exists) {
        return Account.fromMap(doc.data() as Map<String, dynamic>, doc.id);
      }
      return null;
    });
  }

  Stream<Account?> watchAccountByTripId(String tripId) {
    return _accountCollection
        .where('tripId', isEqualTo: tripId)
        .limit(1)
        .snapshots()
        .map((snapshot) {
          if (snapshot.docs.isNotEmpty) {
            final doc = snapshot.docs.first;
            return Account.fromMap(doc.data() as Map<String, dynamic>, doc.id);
          }
          return null;
        });
  }

  Future<void> addMemberToAccount(String accountId, GroupMember member) async {
    try {
      await _membersCollection(
        accountId,
      ).doc(member.userId).set(member.toMap());
    } catch (e, stackTrace) {
      _errorService.logError(
        'account_repository.dart',
        'Erreur lors de l\'ajout du membre: $e',
        stackTrace,
      );
      throw Exception('Impossible d\'ajouter le membre');
    }
  }

  Future<void> removeMemberFromAccount(
    String accountId,
    String memberId,
  ) async {
    try {
      await _membersCollection(accountId).doc(memberId).delete();
    } catch (e, stackTrace) {
      _errorService.logError(
        'account_repository.dart',
        'Erreur lors de la suppression du membre: $e',
        stackTrace,
      );
      throw Exception('Impossible de supprimer le membre');
    }
  }
}
