using Knot.Contracts.Messaging.Application.Abstractions;
using Knot.Contracts.Messaging.Domain;
using Knot.Contracts.Conversations.Application.Abstractions;
using Knot.Contracts.Conversations.Domain;
using Knot.Modules.Conversations.Infrastructure.SignalR;
using Knot.Shared.Kernel;
using MediatR;
using Microsoft.AspNetCore.SignalR;

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

public sealed record EditMessageCommand(
    Guid MessageId,
    Guid ChatId,
    Guid UserId,
    string Content) : ICommand;

public sealed class EditMessageCommandHandler : ICommandHandler<EditMessageCommand>
{
    private readonly IMessageRepository _messageRepository;
    private readonly IChatsUnitOfWork _unitOfWork;
    private readonly IHubContext<ChatHub> _hubContext;

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

    public async Task<Result> Handle(EditMessageCommand request, CancellationToken cancellationToken)
    {
        var message = await _messageRepository.GetByIdAsync(request.MessageId, cancellationToken);
        
        if (message is null)
        {
            return Result.Failure(new Error("Message.NotFound", "Message not found."));
        }

        if (message.SenderId != request.UserId)
        {
            return Result.Failure(new Error("Message.Forbidden", "You can only edit your own messages."));
        }

        if (message.ChatId != request.ChatId)
        {
             return Result.Failure(new Error("Message.InvalidChat", "Message does not belong to this chat."));
        }

        message.Edit(request.Content);

        await _messageRepository.UpdateAsync(message, cancellationToken);
        await _unitOfWork.SaveChangesAsync(cancellationToken);

        // Notify clients
        await _hubContext.Clients.Group(request.ChatId.ToString()).SendAsync("message_edited", new
        {
            messageId = message.Id,
            chatId = message.ChatId,
            content = message.Content,
            isEdited = true
        });

        return Result.Success();
    }
}
