import 'package:equatable/equatable.dart';
import 'package:logger/logger.dart';

/// Enumération représentant les différents statuts possibles d'un ami.
/// Utilisée pour éviter les erreurs de chaîne de caractères et faciliter les comparaisons.
enum FriendStatus { pending, accepted, blocked, unknown }

/// Classe [Friend] représentant un ami avec ses informations de base.
/// Cette classe est conçue pour être utilisée dans des applications de haut niveau
/// avec une gestion robuste des erreurs, des logs avancés, et une immuabilité stricte.
///
/// Chaque instance de [Friend] est immuable et toute modification doit passer par [copyWith].
class Friend extends Equatable {
  final String friendId; // ID unique de l'ami, requis et non-nullable
  final String firstName; // Prénom de l'ami, non-nullable pour garantir une intégrité des données
  final String lastName; // Nom de famille, non-nullable
  final String? email; // Adresse e-mail, optionnelle mais typiquement présente
  final String? imageUrl; // URL de l'image de profil, optionnelle
  final FriendStatus status; // Statut de l'ami, avec une valeur par défaut `unknown`

  /// Logger statique pour suivre toutes les actions et transformations liées à [Friend].
  static final Logger _logger = Logger();

  /// Constructeur de la classe [Friend].
  /// Initialisation avec des valeurs spécifiques pour `firstName` et `lastName`.
  /// La validation des valeurs est incluse pour garantir l'intégrité des données.
  Friend({
    required this.friendId,
    this.firstName = 'Ami inconnu', // Valeur par défaut pour éviter les champs vides
    this.lastName = '',
    this.email,
    this.imageUrl,
    this.status = FriendStatus.unknown,
  }) {
    assert(friendId.isNotEmpty, 'friendId ne doit pas être vide');
    _logger.i('[LOG] Création d\'un objet Friend : ID = $friendId, Nom = $firstName $lastName');
  }

  /// Méthode factory pour créer un objet [Friend] à partir d'un JSON.
  /// Inclut une validation approfondie pour vérifier l'intégrité des données.
  ///
  /// Retourne une instance de [Friend] ou null si les données sont incomplètes.
  factory Friend.fromJson(Map<String, dynamic> json) {
    _logger.i('[LOG] Conversion JSON -> Friend : $json');

    if (json['friendId'] == null || (json['friendId'] as String).isEmpty) {
      _logger.e('[ERROR] friendId manquant ou vide dans le JSON.');
      throw ArgumentError("friendId est requis pour créer un objet Friend");
    }

    return Friend(
      friendId: json['friendId'] as String,
      firstName: json['friendFirstName'] as String? ?? 'Ami inconnu',
      lastName: json['friendLastName'] as String? ?? '',
      email: json['email'] as String?,
      imageUrl: json['imageUrl'] as String?,
      status: _parseStatus(json['status'] as String?),
    );
  }

  /// Méthode privée pour parser le champ `status` en type [FriendStatus].
  /// Retourne [FriendStatus.unknown] si le statut est non reconnu.
  static FriendStatus _parseStatus(String? status) {
    switch (status?.toLowerCase()) {
      case 'pending':
        return FriendStatus.pending;
      case 'accepted':
        return FriendStatus.accepted;
      case 'blocked':
        return FriendStatus.blocked;
      default:
        return FriendStatus.unknown;
    }
  }

  /// Sérialise un objet [Friend] en JSON pour être transmis à l'API.
  /// Les logs incluent le temps de traitement pour les optimisations de performance.
  Map<String, dynamic> toJson() {
    final json = {
      'friendId': friendId,
      'firstName': firstName,
      'lastName': lastName,
      'email': email,
      'imageUrl': imageUrl,
      'status': status.name,
    };
    _logger.i('[LOG] Conversion Friend -> JSON : $json');
    return json;
  }

  /// Méthode [copyWith] pour cloner un objet `Friend` en modifiant certains attributs.
  /// Facilite la modification immuable des propriétés sans affecter l'instance actuelle.
  ///
  /// Log chaque copie pour surveiller l'état des données.
  Friend copyWith({
    String? friendId,
    String? firstName,
    String? lastName,
    String? email,
    String? imageUrl,
    FriendStatus? status,
  }) {
    final newFriend = Friend(
      friendId: friendId ?? this.friendId,
      firstName: firstName ?? this.firstName,
      lastName: lastName ?? this.lastName,
      email: email ?? this.email,
      imageUrl: imageUrl ?? this.imageUrl,
      status: status ?? this.status,
    );
    _logger.i('[LOG] Création d\'une copie modifiée de Friend : ID = ${newFriend.friendId}');
    return newFriend;
  }

  /// Propriétés utilisées pour comparer les objets [Friend],
  /// facilitant l'utilisation dans des listes et des ensembles.
  @override
  List<Object?> get props => [friendId, firstName, lastName, email, imageUrl, status];
}
