using MediatR;
using MktXService.Domain.AggregatesModel.ConversationAggregate;
using MktXService.Domain.AggregatesModel.ContactAggregate;
using MktXService.Infrastructure.ExternalServices.Twitter;

namespace MktXService.API.Application.Commands;

/// <summary>
/// EN: Handler for SendMessageCommand.
/// VI: Handler cho SendMessageCommand.
/// </summary>
public class SendMessageCommandHandler : IRequestHandler<SendMessageCommand, SendMessageResult>
{
    private readonly IConversationRepository _conversationRepository;
    private readonly IContactRepository _contactRepository;
    private readonly ITwitterApiClient _twitterClient;
    private readonly ILogger<SendMessageCommandHandler> _logger;

    public SendMessageCommandHandler(
        IConversationRepository conversationRepository,
        IContactRepository contactRepository,
        ITwitterApiClient twitterClient,
        ILogger<SendMessageCommandHandler> logger)
    {
        _conversationRepository = conversationRepository;
        _contactRepository = contactRepository;
        _twitterClient = twitterClient;
        _logger = logger;
    }

    public async Task<SendMessageResult> Handle(
        SendMessageCommand request,
        CancellationToken cancellationToken)
    {
        var conversation = await _conversationRepository.GetByIdAsync(request.ConversationId);
        if (conversation == null)
            return new SendMessageResult(false, null, null, "Conversation not found");

        try
        {
            // EN: Get contact to find Twitter ID
            // VI: Lấy contact để tìm Twitter ID
            var contact = await _contactRepository.GetByIdAsync(conversation.ContactId);
            if (contact == null)
                return new SendMessageResult(false, null, null, "Contact not found");

            // EN: Send message via Twitter API
            // VI: Gửi tin nhắn qua Twitter API
            var twitterResult = await _twitterClient.SendDirectMessageAsync(
                contact.TwitterUserId,
                request.Content,
                cancellationToken);

            if (!twitterResult.Success)
                return new SendMessageResult(false, null, null, twitterResult.Error);

            // EN: Add message to conversation
            // VI: Thêm tin nhắn vào hội thoại
            var message = conversation.AddMessage(
                "outbound",
                "text",
                request.Content,
                request.IsFromBot,
                twitterResult.MessageId);

            await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

            _logger.LogInformation("Message {MessageId} sent in conversation {ConversationId}",
                message.Id, request.ConversationId);

            return new SendMessageResult(true, message.Id, twitterResult.MessageId, null);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send message in conversation {ConversationId}", request.ConversationId);
            return new SendMessageResult(false, null, null, ex.Message);
        }
    }
}

/// <summary>
/// EN: Handler for CloseConversationCommand.
/// VI: Handler cho CloseConversationCommand.
/// </summary>
public class CloseConversationCommandHandler : IRequestHandler<CloseConversationCommand, bool>
{
    private readonly IConversationRepository _conversationRepository;
    private readonly ILogger<CloseConversationCommandHandler> _logger;

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

    public async Task<bool> Handle(CloseConversationCommand request, CancellationToken cancellationToken)
    {
        var conversation = await _conversationRepository.GetByIdAsync(request.ConversationId);
        if (conversation == null) return false;

        conversation.Close(request.Reason);
        await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation("Conversation {ConversationId} closed", request.ConversationId);
        return true;
    }
}

/// <summary>
/// EN: Handler for AssignConversationCommand.
/// VI: Handler cho AssignConversationCommand.
/// </summary>
public class AssignConversationCommandHandler : IRequestHandler<AssignConversationCommand, bool>
{
    private readonly IConversationRepository _conversationRepository;
    private readonly ILogger<AssignConversationCommandHandler> _logger;

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

    public async Task<bool> Handle(AssignConversationCommand request, CancellationToken cancellationToken)
    {
        var conversation = await _conversationRepository.GetByIdAsync(request.ConversationId);
        if (conversation == null) return false;

        conversation.AssignTo(request.UserId);
        await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation("Conversation {ConversationId} assigned to {UserId}",
            request.ConversationId, request.UserId);
        return true;
    }
}

/// <summary>
/// EN: Handler for ReopenConversationCommand.
/// VI: Handler cho ReopenConversationCommand.
/// </summary>
public class ReopenConversationCommandHandler : IRequestHandler<ReopenConversationCommand, bool>
{
    private readonly IConversationRepository _conversationRepository;

    public ReopenConversationCommandHandler(IConversationRepository conversationRepository)
    {
        _conversationRepository = conversationRepository;
    }

    public async Task<bool> Handle(ReopenConversationCommand request, CancellationToken cancellationToken)
    {
        var conversation = await _conversationRepository.GetByIdAsync(request.ConversationId);
        if (conversation == null) return false;

        conversation.Reopen();
        await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
        return true;
    }
}

/// <summary>
/// EN: Handler for MarkConversationPendingCommand.
/// VI: Handler cho MarkConversationPendingCommand.
/// </summary>
public class MarkConversationPendingCommandHandler : IRequestHandler<MarkConversationPendingCommand, bool>
{
    private readonly IConversationRepository _conversationRepository;

    public MarkConversationPendingCommandHandler(IConversationRepository conversationRepository)
    {
        _conversationRepository = conversationRepository;
    }

    public async Task<bool> Handle(MarkConversationPendingCommand request, CancellationToken cancellationToken)
    {
        var conversation = await _conversationRepository.GetByIdAsync(request.ConversationId);
        if (conversation == null) return false;

        conversation.MarkAsPending();
        await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
        return true;
    }
}
