using MediatR;
using Microsoft.Extensions.Logging;
using WhatsAppService.Domain.AggregatesModel.ConversationAggregate;
using WhatsAppService.Domain.AggregatesModel.WhatsAppAccountAggregate;
using WhatsAppService.Infrastructure.ExternalServices;
using WhatsAppService.Infrastructure.Security;

namespace WhatsAppService.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 IWhatsAppAccountRepository _accountRepository;
    private readonly IWhatsAppCloudApiClient _whatsAppClient;
    private readonly IAccessTokenEncryptionService _encryptionService;
    private readonly ILogger<SendMessageCommandHandler> _logger;

    public SendMessageCommandHandler(
        IConversationRepository conversationRepository,
        IWhatsAppAccountRepository accountRepository,
        IWhatsAppCloudApiClient whatsAppClient,
        IAccessTokenEncryptionService encryptionService,
        ILogger<SendMessageCommandHandler> logger)
    {
        _conversationRepository = conversationRepository ?? throw new ArgumentNullException(nameof(conversationRepository));
        _accountRepository = accountRepository ?? throw new ArgumentNullException(nameof(accountRepository));
        _whatsAppClient = whatsAppClient ?? throw new ArgumentNullException(nameof(whatsAppClient));
        _encryptionService = encryptionService ?? throw new ArgumentNullException(nameof(encryptionService));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

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

            // Check 24h window
            if (!conversation.IsWithinMessagingWindow())
            {
                return new SendMessageResult(false, null, null, "Conversation outside 24h messaging window. Use template message.");
            }

            // Get WhatsApp account
            var account = await _accountRepository.GetByIdAsync(conversation.WhatsAppAccountId, cancellationToken);
            if (account == null || account.Status != WhatsAppAccountStatus.Active)
            {
                return new SendMessageResult(false, null, null, "WhatsApp account not available");
            }

            var accessToken = _encryptionService.Decrypt(account.AccessTokenEncrypted);

            // Create message content
            var content = CreateMessageContent(request);

            // Send via WhatsApp API
            var apiResult = await SendViaApiAsync(account.PhoneNumberId, accessToken, conversation.CustomerWaId, request, cancellationToken);
            
            if (!apiResult.Success)
            {
                return new SendMessageResult(false, null, null, apiResult.ErrorMessage);
            }

            // Add message to conversation
            var message = conversation.AddMessage(content, Message.Directions.Outbound, apiResult.MessageId);
            await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

            _logger.LogInformation(
                "Sent message. ConversationId: {ConversationId}, MessageId: {MessageId}",
                conversation.Id, message.Id);

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

    private static MessageContent CreateMessageContent(SendMessageCommand request)
    {
        return request.MessageType.ToLowerInvariant() switch
        {
            "text" => MessageContent.CreateText(request.Text ?? ""),
            "image" or "video" or "audio" or "document" => 
                MessageContent.CreateMedia(request.MessageType, request.MediaUrl ?? "", request.Caption),
            "interactive" => MessageContent.CreateInteractive(request.Interactive ?? new { }),
            _ => MessageContent.CreateText(request.Text ?? "")
        };
    }

    private async Task<Infrastructure.ExternalServices.SendMessageResult> SendViaApiAsync(
        string phoneNumberId,
        string accessToken,
        string recipientWaId,
        SendMessageCommand request,
        CancellationToken cancellationToken)
    {
        return request.MessageType.ToLowerInvariant() switch
        {
            "text" => await _whatsAppClient.SendTextMessageAsync(
                phoneNumberId, accessToken, recipientWaId, request.Text ?? "", cancellationToken),
            "image" or "video" or "audio" or "document" => await _whatsAppClient.SendMediaMessageAsync(
                phoneNumberId, accessToken, recipientWaId, request.MessageType, request.MediaUrl ?? "", request.Caption, cancellationToken),
            "interactive" => await _whatsAppClient.SendInteractiveMessageAsync(
                phoneNumberId, accessToken, recipientWaId, request.Interactive ?? new { }, cancellationToken),
            _ => await _whatsAppClient.SendTextMessageAsync(
                phoneNumberId, accessToken, recipientWaId, request.Text ?? "", cancellationToken)
        };
    }
}
