using MediatR;
using Microsoft.Extensions.Logging;
using WhatsAppService.Domain.AggregatesModel.ConversationAggregate;
using WhatsAppService.Domain.AggregatesModel.CustomerAggregate;
using WhatsAppService.Domain.AggregatesModel.WhatsAppAccountAggregate;

namespace WhatsAppService.API.Application.Commands;

/// <summary>
/// EN: Handler for ProcessIncomingMessageCommand.
/// VI: Handler cho ProcessIncomingMessageCommand.
/// </summary>
public class ProcessIncomingMessageCommandHandler : IRequestHandler<ProcessIncomingMessageCommand, ProcessIncomingMessageResult>
{
    private readonly IWhatsAppAccountRepository _accountRepository;
    private readonly IConversationRepository _conversationRepository;
    private readonly ICustomerRepository _customerRepository;
    private readonly ILogger<ProcessIncomingMessageCommandHandler> _logger;

    public ProcessIncomingMessageCommandHandler(
        IWhatsAppAccountRepository accountRepository,
        IConversationRepository conversationRepository,
        ICustomerRepository customerRepository,
        ILogger<ProcessIncomingMessageCommandHandler> logger)
    {
        _accountRepository = accountRepository;
        _conversationRepository = conversationRepository;
        _customerRepository = customerRepository;
        _logger = logger;
    }

    public async Task<ProcessIncomingMessageResult> Handle(
        ProcessIncomingMessageCommand request,
        CancellationToken cancellationToken)
    {
        try
        {
            // Find WhatsApp account by phone number ID
            var account = await _accountRepository.GetByPhoneNumberIdAsync(request.PhoneNumberId, cancellationToken);
            if (account == null)
            {
                _logger.LogWarning("No WhatsApp account found for phone number ID: {PhoneNumberId}", request.PhoneNumberId);
                return new ProcessIncomingMessageResult(false, null, null, false, "Account not found");
            }

            var shopId = account.ShopId;
            var isNewConversation = false;

            // Get or create customer
            var customer = await _customerRepository.GetByWaIdAsync(shopId, request.SenderWaId, cancellationToken);
            if (customer == null)
            {
                customer = new Customer(shopId, request.SenderWaId);
                await _customerRepository.AddAsync(customer, cancellationToken);
            }

            // Get or create conversation
            var conversation = await _conversationRepository.GetActiveByCustomerAsync(shopId, request.SenderWaId, cancellationToken);
            if (conversation == null)
            {
                conversation = new Conversation(shopId, request.SenderWaId, account.Id);
                await _conversationRepository.AddAsync(conversation, cancellationToken);
                isNewConversation = true;
            }

            // Create message content based on type
            var content = CreateMessageContent(request);

            // Add message to conversation
            var message = conversation.AddMessage(content, Message.Directions.Inbound, request.MessageId);

            await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

            _logger.LogInformation(
                "Processed incoming message. ConversationId: {ConversationId}, MessageId: {MessageId}, IsNew: {IsNew}",
                conversation.Id, message.Id, isNewConversation);

            return new ProcessIncomingMessageResult(true, conversation.Id, message.Id, isNewConversation, null);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to process incoming message from {SenderWaId}", request.SenderWaId);
            return new ProcessIncomingMessageResult(false, null, null, false, ex.Message);
        }
    }

    private static MessageContent CreateMessageContent(ProcessIncomingMessageCommand request)
    {
        return request.MessageType.ToLowerInvariant() switch
        {
            "text" => MessageContent.CreateText(request.TextBody ?? ""),
            "image" or "video" or "audio" or "document" => 
                MessageContent.CreateMedia(request.MessageType, request.MediaId ?? "", null, request.MediaMimeType),
            "interactive" => MessageContent.CreateInteractive(request.Interactive ?? new { }),
            _ => MessageContent.CreateText(request.TextBody ?? $"[Unsupported: {request.MessageType}]")
        };
    }
}
