using Knot.Contracts.Conversations.Application.Abstractions;
using Knot.Contracts.Conversations.Domain;
using Knot.Contracts.Messaging.Application.Abstractions;
using Knot.Shared.Kernel;
using MediatR;

namespace Knot.Modules.Conversations.Application.Messages.Read;

public sealed record ReadMessagesCommand(Guid ChatId, Guid UserId, Guid LastReadMessageId, long LastReadSequenceId) : ICommand;

public sealed class ReadMessagesCommandHandler : ICommandHandler<ReadMessagesCommand>
{
    private readonly IChatRepository _chatRepository;
    private readonly IChatsUnitOfWork _unitOfWork;
    private readonly IMessageRepository _messageRepository;

    public ReadMessagesCommandHandler(IChatRepository chatRepository, IChatsUnitOfWork unitOfWork, IMessageRepository messageRepository)
    {
        _chatRepository = chatRepository;
        _unitOfWork = unitOfWork;
        _messageRepository = messageRepository;
    }

    public async Task<Result> Handle(ReadMessagesCommand request, CancellationToken cancellationToken)
    {
        var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
        if (chat == null) return Result.Failure(ChatErrors.NotFound);

        var member = chat.Members.FirstOrDefault(m => m.UserId == request.UserId);
        if (member == null) return Result.Failure(ChatErrors.NotMember);

        member.UpdateReadCursor(request.LastReadMessageId, request.LastReadSequenceId);

        // Обновляем ReadByUsers для всех сообщений до LastReadSequenceId
        var messages = await _messageRepository.GetChatMessagesAfterAsync(
            request.ChatId,
            0,
            1000,
            cancellationToken);

        foreach (var message in messages)
        {
            if (message.SequenceId <= request.LastReadSequenceId &&
                message.SenderId != request.UserId &&
                !message.IsReadBy(request.UserId))
            {
                message.MarkAsRead(request.UserId);
            }
        }

        await _unitOfWork.SaveChangesAsync(cancellationToken);

        return Result.Success();
    }
}

