import 'package:dartz/dartz.dart';

import '../../core/constants/env_config.dart';
import '../../core/errors/exceptions.dart';
import '../../core/errors/failures.dart';
import '../../core/utils/app_logger.dart';
import '../../domain/entities/user.dart';
import '../../domain/repositories/user_repository.dart';
import '../datasources/user_remote_data_source.dart';
import '../models/user_model.dart';

/// Implémentation du repository des utilisateurs.
///
/// Cette classe fait le lien entre la couche domaine et la couche données,
/// en convertissant les exceptions en failures et en gérant la transformation
/// entre les modèles de données et les entités de domaine.
///
/// **Usage:**
/// ```dart
/// final repository = UserRepositoryImpl(
///   remoteDataSource: userRemoteDataSource,
/// );
/// final result = await repository.getUser('user123');
/// result.fold(
///   (failure) => print('Erreur: $failure'),
///   (user) => print('Utilisateur: $user'),
/// );
/// ```
class UserRepositoryImpl implements UserRepository {
  /// Crée une nouvelle instance de [UserRepositoryImpl].
  ///
  /// [remoteDataSource] La source de données distante pour les utilisateurs
  UserRepositoryImpl({required this.remoteDataSource});

  /// Source de données distante pour les opérations sur les utilisateurs
  final UserRemoteDataSource remoteDataSource;

  /// Log un message si le mode debug est activé.
  void _log(String message) {
    AppLogger.d(message, tag: 'UserRepositoryImpl');
  }

  /// Récupère un utilisateur par son ID depuis la source de données distante.
  ///
  /// [id] L'identifiant de l'utilisateur
  ///
  /// Returns [Right] avec l'utilisateur si succès, [Left] avec une [Failure] si erreur
  ///
  /// **Exemple:**
  /// ```dart
  /// final result = await repository.getUser('user123');
  /// result.fold(
  ///   (failure) => handleError(failure),
  ///   (user) => displayUser(user),
  /// );
  /// ```
  @override
  Future<Either<Failure, User>> getUser(String id) async {
    _log('Récupération de l\'utilisateur $id');

    try {
      if (id.isEmpty) {
        return const Left(ValidationFailure(message: 
          'L\'ID utilisateur ne peut pas être vide',
          field: 'id',
        ));
      }

      final userModel = await remoteDataSource.getUser(id);
      _log('Utilisateur $id récupéré avec succès');
      return Right(userModel.toEntity());
    } on UserNotFoundException catch (e) {
      _log('Utilisateur $id non trouvé: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        code: 'USER_NOT_FOUND',
        statusCode: 404,
      ));
    } on ValidationException catch (e) {
      _log('Erreur de validation: ${e.message}');
      return Left(ValidationFailure(message: 
        e.message,
        field: e.field,
      ));
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la récupération de l\'utilisateur: $e',
      ));
    }
  }

  /// Authentifie un utilisateur avec son email et mot de passe.
  ///
  /// [email] L'adresse email de l'utilisateur
  /// [password] Le mot de passe de l'utilisateur
  ///
  /// Returns [Right] avec l'utilisateur authentifié si succès,
  /// [Left] avec une [Failure] si erreur
  ///
  /// **Exemple:**
  /// ```dart
  /// final result = await repository.authenticateUser(
  ///   'user@example.com',
  ///   'password123',
  /// );
  /// ```
  Future<Either<Failure, User>> authenticateUser(
    String email,
    String password,
  ) async {
    _log('Authentification pour: $email');

    try {
      if (email.isEmpty || password.isEmpty) {
        return const Left(ValidationFailure(message: 
          'L\'email et le mot de passe sont requis',
        ));
      }

      final userModel = await remoteDataSource.authenticateUser(email, password);
      _log('Authentification réussie pour: ${userModel.email}');
      return Right(userModel.toEntity());
    } on UnauthorizedException catch (e) {
      _log('Authentification échouée: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } on ValidationException catch (e) {
      _log('Erreur de validation: ${e.message}');
      return Left(ValidationFailure(message: 
        e.message,
        field: e.field,
      ));
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de l\'authentification: $e',
      ));
    }
  }

  /// Crée un nouvel utilisateur.
  ///
  /// [user] L'entité utilisateur à créer
  ///
  /// Returns [Right] avec l'utilisateur créé si succès,
  /// [Left] avec une [Failure] si erreur
  Future<Either<Failure, User>> createUser(User user) async {
    _log('Création d\'un nouvel utilisateur: ${user.email}');

    try {
      final userModel = UserModel(
        userId: user.userId,
        userLastName: user.userLastName,
        userFirstName: user.userFirstName,
        email: user.email,
        motDePasse: user.motDePasse,
        profileImageUrl: user.profileImageUrl,
        eventsCount: user.eventsCount,
        friendsCount: user.friendsCount,
        postsCount: user.postsCount,
        visitedPlacesCount: user.visitedPlacesCount,
      );

      final createdUser = await remoteDataSource.createUser(userModel);
      _log('Utilisateur créé avec succès: ${createdUser.userId}');
      return Right(createdUser.toEntity());
    } on ConflictException catch (e) {
      _log('Conflit lors de la création: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        code: 'CONFLICT',
        statusCode: 409,
      ));
    } on ValidationException catch (e) {
      _log('Erreur de validation: ${e.message}');
      return Left(ValidationFailure(message: 
        e.message,
        field: e.field,
      ));
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la création de l\'utilisateur: $e',
      ));
    }
  }

  /// Met à jour un utilisateur existant.
  ///
  /// [user] L'entité utilisateur avec les nouvelles données
  ///
  /// Returns [Right] avec l'utilisateur mis à jour si succès,
  /// [Left] avec une [Failure] si erreur
  Future<Either<Failure, User>> updateUser(User user) async {
    _log('Mise à jour de l\'utilisateur ${user.userId}');

    try {
      final userModel = UserModel(
        userId: user.userId,
        userLastName: user.userLastName,
        userFirstName: user.userFirstName,
        email: user.email,
        motDePasse: user.motDePasse,
        profileImageUrl: user.profileImageUrl,
        eventsCount: user.eventsCount,
        friendsCount: user.friendsCount,
        postsCount: user.postsCount,
        visitedPlacesCount: user.visitedPlacesCount,
      );

      final updatedUser = await remoteDataSource.updateUser(userModel);
      _log('Utilisateur ${user.userId} mis à jour avec succès');
      return Right(updatedUser.toEntity());
    } on UserNotFoundException catch (e) {
      _log('Utilisateur non trouvé: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        code: 'USER_NOT_FOUND',
        statusCode: 404,
      ));
    } on ValidationException catch (e) {
      _log('Erreur de validation: ${e.message}');
      return Left(ValidationFailure(message: 
        e.message,
        field: e.field,
      ));
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la mise à jour de l\'utilisateur: $e',
      ));
    }
  }

  /// Supprime un utilisateur.
  ///
  /// [id] L'identifiant de l'utilisateur à supprimer
  ///
  /// Returns [Right] avec `null` si succès, [Left] avec une [Failure] si erreur
  Future<Either<Failure, void>> deleteUser(String id) async {
    _log('Suppression de l\'utilisateur $id');

    try {
      if (id.isEmpty) {
        return const Left(ValidationFailure(message: 
          'L\'ID utilisateur ne peut pas être vide',
          field: 'id',
        ));
      }

      await remoteDataSource.deleteUser(id);
      _log('Utilisateur $id supprimé avec succès');
      return const Right(null);
    } on UserNotFoundException catch (e) {
      _log('Utilisateur non trouvé: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        code: 'USER_NOT_FOUND',
        statusCode: 404,
      ));
    } on ValidationException catch (e) {
      _log('Erreur de validation: ${e.message}');
      return Left(ValidationFailure(message: 
        e.message,
        field: e.field,
      ));
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la suppression de l\'utilisateur: $e',
      ));
    }
  }
}

