import 'package:flutter/material.dart'; import 'package:logger/logger.dart'; import '../../domain/entities/friend.dart'; import '../../data/repositories/friends_repository_impl.dart'; /// [FriendsProvider] est un `ChangeNotifier` qui gère la logique de gestion des amis. /// Il utilise [FriendsRepositoryImpl] pour interagir avec l'API et assure la gestion des états, /// comme le chargement, la pagination et les erreurs éventuelles. class FriendsProvider with ChangeNotifier { final FriendsRepositoryImpl friendsRepository; final Logger _logger = Logger(); // Logger pour suivre toutes les actions. // Liste privée des amis récupérée depuis l'API List _friendsList = []; bool _isLoading = false; // Indique si une opération de chargement est en cours bool _hasMore = true; // Indique s'il reste des amis à charger int _currentPage = 0; final int _friendsPerPage = 10; // Nombre d'amis par page pour la pagination /// Constructeur de [FriendsProvider] qui requiert une instance de [FriendsRepositoryImpl]. FriendsProvider({required this.friendsRepository}); // Getters pour accéder aux états depuis l'interface utilisateur bool get isLoading => _isLoading; bool get hasMore => _hasMore; List get friendsList => _friendsList; /// Récupère la liste paginée des amis pour un utilisateur donné. /// /// [userId] : L'identifiant unique de l'utilisateur. /// [loadMore] : Indique s'il s'agit d'une demande de chargement supplémentaire pour la pagination. /// /// Cette méthode : /// - Vérifie si un chargement est déjà en cours. /// - Initialise ou poursuit la pagination. /// - Exclut l'utilisateur lui-même de la liste. /// - Gère les erreurs et logue chaque étape pour une traçabilité complète. Future fetchFriends(String userId, {bool loadMore = false}) async { if (_isLoading) { _logger.w('[LOG] Chargement déjà en cours, annulation de la nouvelle demande.'); return; } _isLoading = true; notifyListeners(); _logger.i('[LOG] Début du chargement des amis pour l\'utilisateur $userId.'); // Réinitialisation uniquement si ce n'est pas un chargement supplémentaire if (!loadMore) { _friendsList = []; _currentPage = 0; _hasMore = true; _logger.i('[LOG] Réinitialisation de la pagination et de la liste des amis.'); } try { _logger.i('[LOG] Chargement de la page $_currentPage des amis pour l\'utilisateur $userId.'); final newFriends = await friendsRepository.fetchFriends(userId, _currentPage, _friendsPerPage); if (newFriends.isEmpty) { _hasMore = false; _logger.i('[LOG] Fin de liste atteinte, plus d\'amis à charger.'); } else { for (var friend in newFriends) { if (friend.friendId != userId) { _friendsList.add(friend); _logger.i("[LOG] Ajout de l'ami : ID = ${friend.friendId}, Nom = ${friend.friendFirstName} ${friend.friendLastName}"); } else { _logger.w("[WARN] Exclusion de l'utilisateur lui-même de la liste d'amis : ${friend.friendId}"); } } _currentPage++; _logger.i('[LOG] Page suivante préparée pour le prochain chargement, page actuelle : $_currentPage'); } } catch (e) { _logger.e('[ERROR] Erreur lors de la récupération des amis : $e'); } finally { _isLoading = false; _logger.i('[LOG] Fin du chargement des amis.'); notifyListeners(); } } /// Supprime un ami dans l'API et met à jour la liste localement. /// /// [friendId] : Identifiant unique de l'ami à supprimer. /// /// Loggue chaque étape pour assurer un suivi précis de l'opération. Future removeFriend(String friendId) async { try { _logger.i('[LOG] Tentative de suppression de l\'ami avec l\'ID : $friendId'); await friendsRepository.removeFriend(friendId); _friendsList.removeWhere((friend) => friend.friendId == friendId); _logger.i('[LOG] Ami supprimé localement avec succès : $friendId'); } catch (e) { _logger.e('[ERROR] Erreur lors de la suppression de l\'ami : $e'); } finally { notifyListeners(); } } /// Récupère les détails d'un ami via l'API. /// /// [userId] : L'identifiant de l'utilisateur connecté. /// [friendId] : Identifiant unique de l'ami. /// /// Retourne un `Future` contenant les détails ou `null` en cas d'erreur. Future fetchFriendDetails(String userId, String friendId) async { try { _logger.i('[LOG] Tentative de récupération des détails de l\'ami avec l\'ID : $friendId'); final friendDetails = await friendsRepository.getFriendDetails(friendId, userId); if (friendDetails != null) { _logger.i('[LOG] Détails de l\'ami récupérés avec succès : ${friendDetails.friendId}'); } else { _logger.w('[LOG] Détails de l\'ami introuvables pour l\'ID : $friendId'); } return friendDetails; } catch (e) { _logger.e('[ERROR] Exception lors de la récupération des détails de l\'ami : $e'); return null; } } /// Convertit un statut sous forme de chaîne en [FriendStatus]. /// /// [status] : Le statut sous forme de chaîne. /// /// Retourne un [FriendStatus] correspondant, ou `FriendStatus.unknown` si non reconnu. FriendStatus _convertToFriendStatus(String status) { switch (status.toLowerCase()) { case 'pending': return FriendStatus.pending; case 'accepted': return FriendStatus.accepted; case 'blocked': return FriendStatus.blocked; default: return FriendStatus.unknown; } } /// Met à jour le statut d'un ami (par exemple : accepter, bloquer). /// /// [friendId] : Identifiant unique de l'ami. /// [status] : Nouveau statut pour l'ami sous forme de chaîne de caractères. /// /// Loggue l'action, convertit le statut en `FriendStatus`, et met à jour la liste localement. Future updateFriendStatus(String friendId, String status) async { try { _logger.i('[LOG] Tentative de mise à jour du statut de l\'ami avec l\'ID : $friendId'); // Conversion du `String` en `FriendStatus` pour l'update locale final friendStatus = _convertToFriendStatus(status); await friendsRepository.updateFriendStatus(friendId, status); // Mise à jour locale de la liste pour afficher le changement de statut final friendIndex = _friendsList.indexWhere((friend) => friend.friendId == friendId); if (friendIndex != -1) { _friendsList[friendIndex] = _friendsList[friendIndex].copyWith(status: friendStatus); _logger.i('[LOG] Statut de l\'ami mis à jour localement pour l\'ID : $friendId'); } } catch (e) { _logger.e('[ERROR] Erreur lors de la mise à jour du statut de l\'ami : $e'); } finally { notifyListeners(); } } }