using global::Knot.Contracts.Conversations.Application.Abstractions;
using global::Knot.Contracts.Conversations.Domain;
using global::Knot.Modules.Conversations.Infrastructure.SignalR;
using global::Knot.Shared.Kernel;
using MediatR;
using Microsoft.AspNetCore.SignalR;
using MessagingMessageRepository = Knot.Contracts.Messaging.Application.Abstractions.IMessageRepository;

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

public sealed record DeleteMessagesCommand(
    Guid ChatId,
    Guid UserId,
    List<Guid> MessageIds,
    bool DeleteForAll) : ICommand;

public sealed class DeleteMessagesCommandHandler : ICommandHandler<DeleteMessagesCommand>
{
    private readonly MessagingMessageRepository _messageRepository;
    private readonly IChatsUnitOfWork _unitOfWork;
    private readonly IHubContext<ChatHub> _hubContext;

    public DeleteMessagesCommandHandler(
        MessagingMessageRepository messageRepository,
        IChatsUnitOfWork unitOfWork,
        IHubContext<ChatHub> hubContext)
    {
        _messageRepository = messageRepository;
        _unitOfWork = unitOfWork;
        _hubContext = hubContext;
    }

    public async Task<global::Knot.Shared.Kernel.Result> Handle(DeleteMessagesCommand request, CancellationToken cancellationToken)
    {
        foreach (var id in request.MessageIds)
        {
            var message = await _messageRepository.GetByIdAsync(id, cancellationToken);
            if (message is null || message.ChatId != request.ChatId)
            {
                continue;
            }

            if (request.DeleteForAll)
            {
                // Only message sender can delete for everyone
                if (message.SenderId == request.UserId)
                {
                    message.Delete();
                }
                else
                {
                    // If not the sender, just delete for current user
                    message.DeleteForUser(request.UserId);
                }
            }
            else
            {
                message.DeleteForUser(request.UserId);
            }

            await _messageRepository.UpdateAsync(message, cancellationToken);
        }

        // Notify all clients in the chat about the deletion
        await _hubContext.Clients.Group(request.ChatId.ToString()).SendAsync("messages_deleted", new
        {
            chatId = request.ChatId,
            messageIds = request.MessageIds,
            deleteForAll = request.DeleteForAll
        });

        return global::Knot.Shared.Kernel.Result.Success();
    }
}
