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 getUserById(String uid) async { try { final doc = await _firestore.collection('users').doc(uid).get(); if (doc.exists) { final data = doc.data() as Map; 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 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 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 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 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> getUsersByIds(List 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 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 []; } } }