import 'package:dartz/dartz.dart';

import '../../core/errors/exceptions.dart';
import '../../core/errors/failures.dart';
import '../../core/utils/app_logger.dart';
import '../../domain/entities/chat_message.dart';
import '../../domain/entities/conversation.dart';
import '../../domain/repositories/chat_repository.dart';
import '../datasources/chat_remote_data_source.dart';

/// Implémentation du repository de chat.
///
/// 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 = ChatRepositoryImpl(
///   remoteDataSource: chatRemoteDataSource,
/// );
/// final result = await repository.getConversations('userId');
/// result.fold(
///   (failure) => print('Erreur: $failure'),
///   (conversations) => print('${conversations.length} conversations'),
/// );
/// ```
class ChatRepositoryImpl implements ChatRepository {
  /// Crée une nouvelle instance de [ChatRepositoryImpl].
  ///
  /// [remoteDataSource] La source de données distante pour le chat
  ChatRepositoryImpl({required this.remoteDataSource});

  /// Source de données distante pour les opérations de chat
  final ChatRemoteDataSource remoteDataSource;

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

  @override
  Future<Either<Failure, List<Conversation>>> getConversations(
    String userId,
  ) async {
    _log('Récupération des conversations pour $userId');

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

      final conversationModels = await remoteDataSource.getConversations(userId);
      final conversations = conversationModels.map((model) => model.toEntity()).toList();
      _log('${conversations.length} conversations récupérées');
      return Right(conversations);
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } on UnauthorizedException catch (e) {
      _log('Non autorisé: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la récupération des conversations: $e',
      ));
    }
  }

  @override
  Future<Either<Failure, Conversation>> getOrCreateConversation(
    String userId,
    String participantId,
  ) async {
    _log('Récupération/création conversation entre $userId et $participantId');

    try {
      if (userId.isEmpty || participantId.isEmpty) {
        return const Left(ValidationFailure(message: 
          'Les IDs utilisateur et participant sont requis',
        ));
      }

      if (userId == participantId) {
        return const Left(ValidationFailure(message: 
          'Impossible de créer une conversation avec soi-même',
        ));
      }

      final conversationModel = await remoteDataSource.getOrCreateConversation(
        userId,
        participantId,
      );
      _log('Conversation récupérée/créée avec succès');
      return Right(conversationModel.toEntity());
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } on UnauthorizedException catch (e) {
      _log('Non autorisé: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la récupération/création de la conversation: $e',
      ));
    }
  }

  @override
  Future<Either<Failure, List<ChatMessage>>> getMessages(
    String conversationId, {
    int page = 0,
    int size = 50,
  }) async {
    _log('Récupération des messages de $conversationId (page: $page)');

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

      final messageModels = await remoteDataSource.getMessages(
        conversationId,
        page: page,
        size: size,
      );
      final messages = messageModels.map((model) => model.toEntity()).toList();
      _log('${messages.length} messages récupérés');
      return Right(messages);
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } on UnauthorizedException catch (e) {
      _log('Non autorisé: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la récupération des messages: $e',
      ));
    }
  }

  @override
  Future<Either<Failure, ChatMessage>> sendMessage({
    required String senderId,
    required String recipientId,
    required String content,
    String? messageType,
    String? mediaUrl,
  }) async {
    _log('Envoi d\'un message de $senderId à $recipientId');

    try {
      if (senderId.isEmpty || recipientId.isEmpty) {
        return const Left(ValidationFailure(message: 
          'Les IDs expéditeur et destinataire sont requis',
        ));
      }

      if (content.isEmpty) {
        return const Left(ValidationFailure(message: 
          'Le contenu du message ne peut pas être vide',
          field: 'content',
        ));
      }

      if (senderId == recipientId) {
        return const Left(ValidationFailure(message: 
          'Impossible d\'envoyer un message à soi-même',
        ));
      }

      final messageModel = await remoteDataSource.sendMessage(
        senderId: senderId,
        recipientId: recipientId,
        content: content,
        messageType: messageType,
        mediaUrl: mediaUrl,
      );
      _log('Message envoyé avec succès');
      return Right(messageModel.toEntity());
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } on UnauthorizedException catch (e) {
      _log('Non autorisé: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de l\'envoi du message: $e',
      ));
    }
  }

  @override
  Future<Either<Failure, void>> markMessageAsRead(String messageId) async {
    _log('Marquage du message $messageId comme lu');

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

      await remoteDataSource.markMessageAsRead(messageId);
      _log('Message marqué comme lu');
      return const Right(null);
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } on UnauthorizedException catch (e) {
      _log('Non autorisé: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors du marquage du message: $e',
      ));
    }
  }

  @override
  Future<Either<Failure, void>> markConversationAsRead(
    String conversationId,
    String userId,
  ) async {
    _log('Marquage de tous les messages de $conversationId comme lus');

    try {
      if (conversationId.isEmpty || userId.isEmpty) {
        return const Left(ValidationFailure(message: 
          'Les IDs conversation et utilisateur sont requis',
        ));
      }

      await remoteDataSource.markConversationAsRead(conversationId, userId);
      _log('Conversation marquée comme lue');
      return const Right(null);
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } on UnauthorizedException catch (e) {
      _log('Non autorisé: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors du marquage de la conversation: $e',
      ));
    }
  }

  @override
  Future<Either<Failure, void>> deleteMessage(String messageId) async {
    _log('Suppression du message $messageId');

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

      await remoteDataSource.deleteMessage(messageId);
      _log('Message supprimé');
      return const Right(null);
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } on UnauthorizedException catch (e) {
      _log('Non autorisé: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la suppression du message: $e',
      ));
    }
  }

  @override
  Future<Either<Failure, void>> deleteConversation(String conversationId) async {
    _log('Suppression de la conversation $conversationId');

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

      await remoteDataSource.deleteConversation(conversationId);
      _log('Conversation supprimée');
      return const Right(null);
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } on UnauthorizedException catch (e) {
      _log('Non autorisé: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la suppression de la conversation: $e',
      ));
    }
  }

  @override
  Future<Either<Failure, int>> getUnreadMessagesCount(String userId) async {
    _log('Récupération du nombre de messages non lus pour $userId');

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

      final count = await remoteDataSource.getUnreadMessagesCount(userId);
      _log('$count messages non lus');
      return Right(count);
    } on ServerException catch (e) {
      _log('Erreur serveur: ${e.message}');
      return Left(ServerFailure(
        message: e.message,
        statusCode: e.statusCode,
      ));
    } on UnauthorizedException catch (e) {
      _log('Non autorisé: ${e.message}');
      return Left(AuthenticationFailure(
        message: e.message,
        code: 'UNAUTHORIZED',
      ));
    } catch (e) {
      _log('Erreur inattendue: $e');
      return Left(ServerFailure(
        message: 'Erreur lors de la récupération du nombre de messages non lus: $e',
      ));
    }
  }
}
