import 'package:cloud_firestore/cloud_firestore.dart';
import '../models/user.dart';
import '../services/auth_service.dart';
import '../services/error_service.dart';

/// Repository for user data operations in Firestore.
///
/// This repository provides methods for CRUD operations on user data,
/// including retrieving users by ID or email, updating user information,
/// and managing user profiles in the Firestore database.
class UserRepository {
  /// Firestore instance for database operations.
  final FirebaseFirestore _firestore;

  /// Authentication service for user-related operations.
  final AuthService _authService;

  final _errorService = ErrorService();

  /// Creates a new [UserRepository] with optional dependencies.
  ///
  /// If [firestore] or [authService] are not provided, default instances will be used.
  UserRepository({FirebaseFirestore? firestore, AuthService? authService})
    : _firestore = firestore ?? FirebaseFirestore.instance,
      _authService = authService ?? AuthService();

  /// Retrieves a user by their unique ID.
  ///
  /// Fetches the user document from Firestore and converts it to a [User] model.
  ///
  /// [uid] - The unique user identifier
  ///
  /// Returns the [User] model if found, null otherwise.
  /// Throws an exception if the operation fails.
  Future<User?> getUserById(String uid) async {
    try {
      final doc = await _firestore.collection('users').doc(uid).get();
      if (doc.exists) {
        final data = doc.data() as Map<String, dynamic>;
        return User.fromMap({...data, 'id': uid});
      }
      return null;
    } catch (e, stackTrace) {
      _errorService.logError(
        'UserRepository',
        'Error retrieving user: $e',
        stackTrace,
      );
      throw Exception('Impossible de récupérer l\'utilisateur');
    }
  }

  /// Retrieves a user by their email address.
  ///
  /// Searches the users collection for a matching email address.
  /// Email comparison is case-insensitive after trimming whitespace.
  ///
  /// [email] - The email address to search for
  ///
  /// Returns the first [User] found with the matching email, null if not found.
  /// Throws an exception if the operation fails.
  Future<User?> getUserByEmail(String email) async {
    try {
      final querySnapshot = await _firestore
          .collection('users')
          .where('email', isEqualTo: email.trim())
          .limit(1)
          .get();

      if (querySnapshot.docs.isNotEmpty) {
        final doc = querySnapshot.docs.first;
        final data = doc.data();
        return User.fromMap({...data, 'id': doc.id});
      }
      return null;
    } catch (e, stackTrace) {
      _errorService.logError(
        'UserRepository',
        'Error searching for user: $e',
        stackTrace,
      );
      throw Exception('Impossible de trouver l\'utilisateur');
    }
  }

  /// Updates an existing user in Firestore.
  ///
  /// Updates the user document with the provided user data.
  ///
  /// [user] - The user object containing updated information
  ///
  /// Returns true if the update was successful, false otherwise.
  Future<bool> updateUser(User user) async {
    try {
      await _firestore.collection('users').doc(user.id).update(user.toMap());

      // Mettre à jour le displayName dans Firebase Auth
      await _authService.updateDisplayName(displayName: user.fullName);

      return true;
    } catch (e, stackTrace) {
      _errorService.logError(
        'UserRepository',
        'Erreur lors de la mise à jour: $e',
        stackTrace,
      );
      throw Exception('Impossible de mettre à jour l\'utilisateur');
    }
  }

  // Supprimer un utilisateur
  Future<bool> deleteUser(String uid) async {
    try {
      await _firestore.collection('users').doc(uid).delete();
      // Note: Vous devrez également supprimer le compte Firebase Auth
      return true;
    } catch (e, stackTrace) {
      _errorService.logError(
        'UserRepository',
        'Erreur lors de la suppression: $e',
        stackTrace,
      );
      throw Exception('Impossible de supprimer l\'utilisateur');
    }
  }

  // Changer le mot de passe
  Future<bool> changePassword({
    required String currentPassword,
    required String newPassword,
  }) async {
    try {
      final currentUser = _authService.currentUser;
      if (currentUser?.email == null) {
        throw Exception('Utilisateur non connecté ou email non disponible');
      }

      await _authService.resetPasswordFromCurrentPassword(
        email: currentUser!.email!,
        currentPassword: currentPassword,
        newPassword: newPassword,
      );
      return true;
    } catch (e, stackTrace) {
      _errorService.logError(
        'UserRepository',
        'Erreur lors du changement de mot de passe: $e',
        stackTrace,
      );
      throw Exception('Impossible de changer le mot de passe');
    }
  }

  // Récupérer plusieurs utilisateurs par leurs IDs
  Future<List<User>> getUsersByIds(List<String> uids) async {
    if (uids.isEmpty) return [];

    try {
      // Firestore 'in' query supports up to 10 values.
      // If we have more, we need to split into chunks.
      List<User> users = [];

      // Remove duplicates
      final uniqueIds = uids.toSet().toList();

      // Split into chunks of 10
      for (var i = 0; i < uniqueIds.length; i += 10) {
        final end = (i + 10 < uniqueIds.length) ? i + 10 : uniqueIds.length;
        final chunk = uniqueIds.sublist(i, end);

        final querySnapshot = await _firestore
            .collection('users')
            .where(FieldPath.documentId, whereIn: chunk)
            .get();

        for (var doc in querySnapshot.docs) {
          final data = doc.data();
          users.add(User.fromMap({...data, 'id': doc.id}));
        }
      }

      return users;
    } catch (e, stackTrace) {
      _errorService.logError(
        'UserRepository',
        'Error retrieving users by IDs: $e',
        stackTrace,
      );
      return [];
    }
  }
}
