using MediatR;
using ChatService.Domain.AggregatesModel.ConversationAggregate;
using ChatService.Domain.AggregatesModel.UserAggregate;

namespace ChatService.API.Application.Queries.Messages;

/// <summary>
/// EN: Handler for GetMessagesQuery.
/// VI: Handler cho GetMessagesQuery.
/// </summary>
public class GetMessagesQueryHandler : IRequestHandler<GetMessagesQuery, GetMessagesResult>
{
    private readonly IConversationRepository _conversationRepository;
    private readonly IChatUserRepository _chatUserRepository;
    private readonly ILogger<GetMessagesQueryHandler> _logger;

    public GetMessagesQueryHandler(
        IConversationRepository conversationRepository,
        IChatUserRepository chatUserRepository,
        ILogger<GetMessagesQueryHandler> logger)
    {
        _conversationRepository = conversationRepository;
        _chatUserRepository = chatUserRepository;
        _logger = logger;
    }

    public async Task<GetMessagesResult> Handle(GetMessagesQuery request, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Getting messages for conversation {ConversationId}, user {UserId}",
            request.ConversationId, request.UserId);

        // EN: Verify user is participant
        // VI: Xác thực user là participant
        var isParticipant = await _conversationRepository.IsUserParticipantAsync(
            request.ConversationId, request.UserId, cancellationToken);

        if (!isParticipant)
        {
            throw new UnauthorizedAccessException("User is not a participant in this conversation");
        }

        var (messages, totalCount) = await _conversationRepository.GetMessagesPaginatedAsync(
            request.ConversationId, request.Page, request.PageSize, request.Before, cancellationToken);

        var messageList = messages.ToList();

        // EN: Get sender info for all messages
        // VI: Lấy thông tin người gửi cho tất cả tin nhắn
        var senderIds = messageList.Select(m => m.SenderId).Distinct().ToList();
        var users = await _chatUserRepository.GetByIdsAsync(senderIds, cancellationToken);
        var userDict = users.ToDictionary(u => u.Id);

        var messageDtos = messageList.Select(m => new MessageDto(
            m.Id,
            m.ConversationId,
            m.SenderId,
            userDict.TryGetValue(m.SenderId, out var user) ? user.DisplayName : "Unknown",
            m.EncryptedContent,
            m.Nonce,
            m.AuthTag,
            m.Type.Name,
            m.Status.Name,
            m.Metadata,
            m.ReplyToMessageId,
            m.CreatedAt,
            m.DeliveredAt,
            m.ReadAt
        )).ToList();

        var totalPages = (int)Math.Ceiling((double)totalCount / request.PageSize);
        var hasMore = request.Page < totalPages;

        return new GetMessagesResult(
            messageDtos,
            totalCount,
            request.Page,
            request.PageSize,
            hasMore
        );
    }
}
