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<Friend> _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<Friend> 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.
  ///
  /// En cas d'erreur, logue l'exception et gère l'état `isLoading`.
  Future<void> 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.');

    if (!loadMore) {
      // Réinitialisation de la liste et de la pagination si ce n'est pas un chargement supplémentaire
      _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 {
        _friendsList.addAll(newFriends);
        _currentPage++;
        _logger.i('[LOG] Amis ajoutés à la liste. 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<void> 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<Friend?>` contenant les détails ou `null` en cas d'erreur.
  Future<Friend?> 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<void> 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();
    }
  }
}
