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

namespace ChatService.API.Application.Commands.Messages;

/// <summary>
/// EN: Handler for MarkMessagesReadCommand.
/// VI: Handler cho MarkMessagesReadCommand.
/// </summary>
public class MarkMessagesReadCommandHandler : IRequestHandler<MarkMessagesReadCommand, MarkMessagesReadResult>
{
    private readonly IConversationRepository _conversationRepository;
    private readonly ILogger<MarkMessagesReadCommandHandler> _logger;

    public MarkMessagesReadCommandHandler(
        IConversationRepository conversationRepository,
        ILogger<MarkMessagesReadCommandHandler> logger)
    {
        _conversationRepository = conversationRepository;
        _logger = logger;
    }

    public async Task<MarkMessagesReadResult> Handle(MarkMessagesReadCommand request, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Marking messages as read for user {UserId} in conversation {ConversationId}",
            request.UserId, request.ConversationId);

        var conversation = await _conversationRepository.GetByIdWithMessagesAsync(request.ConversationId, cancellationToken);

        if (conversation == null)
        {
            throw new InvalidOperationException($"Conversation {request.ConversationId} not found");
        }

        // EN: Get participant
        // VI: Lấy participant
        var participant = conversation.Participants.FirstOrDefault(p => p.UserId == request.UserId && p.IsActive);
        if (participant == null)
        {
            throw new InvalidOperationException("User is not a participant in this conversation");
        }

        int markedCount = 0;
        DateTime? lastReadAt = null;

        if (request.LastReadMessageId.HasValue)
        {
            // EN: Mark up to specific message
            // VI: Đánh dấu đến tin nhắn cụ thể
            participant.UpdateLastRead(request.LastReadMessageId.Value);
            lastReadAt = participant.LastReadAt;

            // EN: Count messages marked
            // VI: Đếm số tin nhắn đã đánh dấu
            var message = conversation.Messages.FirstOrDefault(m => m.Id == request.LastReadMessageId.Value);
            if (message != null)
            {
                markedCount = conversation.Messages
                    .Count(m => m.SenderId != request.UserId && m.CreatedAt <= message.CreatedAt);
            }
        }
        else if (request.ReadUpTo.HasValue)
        {
            // EN: Mark all messages up to timestamp
            // VI: Đánh dấu tất cả tin nhắn đến thời điểm
            var latestMessage = conversation.Messages
                .Where(m => m.CreatedAt <= request.ReadUpTo.Value)
                .OrderByDescending(m => m.CreatedAt)
                .FirstOrDefault();

            if (latestMessage != null)
            {
                participant.UpdateLastRead(latestMessage.Id);
                lastReadAt = participant.LastReadAt;
                markedCount = conversation.Messages
                    .Count(m => m.SenderId != request.UserId && m.CreatedAt <= request.ReadUpTo.Value);
            }
        }
        else
        {
            // EN: Mark all messages as read
            // VI: Đánh dấu tất cả tin nhắn
            var latestMessage = conversation.Messages
                .OrderByDescending(m => m.CreatedAt)
                .FirstOrDefault();

            if (latestMessage != null)
            {
                participant.UpdateLastRead(latestMessage.Id);
                lastReadAt = participant.LastReadAt;
                markedCount = conversation.Messages
                    .Count(m => m.SenderId != request.UserId);
            }
        }

        _conversationRepository.Update(conversation);
        await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation("Marked {Count} messages as read", markedCount);

        return new MarkMessagesReadResult(markedCount, lastReadAt);
    }
}
