using MediatR;
using Microsoft.Extensions.Logging;
using MktZaloService.Domain.AggregatesModel.ConversationAggregate;
using MktZaloService.Domain.Enums;
using MktZaloService.Domain.Exceptions;
using MktZaloService.Infrastructure.Zalo;

namespace MktZaloService.API.Application.Commands.Messages;

/// <summary>
/// EN: Handler for sending messages to Zalo users.
/// VI: Handler để gửi tin nhắn đến người dùng Zalo.
/// </summary>
public class SendMessageCommandHandler : IRequestHandler<SendMessageCommand, SendMessageResult>
{
    private readonly IConversationRepository _conversationRepository;
    private readonly IZaloOfficialAccountClient _zaloClient;
    private readonly ILogger<SendMessageCommandHandler> _logger;

    public SendMessageCommandHandler(
        IConversationRepository conversationRepository,
        IZaloOfficialAccountClient zaloClient,
        ILogger<SendMessageCommandHandler> logger)
    {
        _conversationRepository = conversationRepository;
        _zaloClient = zaloClient;
        _logger = logger;
    }

    public async Task<SendMessageResult> Handle(
        SendMessageCommand request,
        CancellationToken cancellationToken)
    {
        // EN: Get conversation / VI: Lấy cuộc hội thoại
        var conversation = await _conversationRepository.GetByIdAsync(request.ConversationId, cancellationToken);

        if (conversation == null)
        {
            return new SendMessageResult(false, Error: "Conversation not found");
        }

        try
        {
            // EN: Send message via Zalo API / VI: Gửi tin nhắn qua Zalo API
            var response = await _zaloClient.SendTextMessageAsync(
                conversation.ZaloUserId,
                request.Text,
                cancellationToken);

            if (response.Error != 0)
            {
                _logger.LogWarning(
                    "EN: Zalo API error {Error}: {Message}. VI: Lỗi Zalo API {Error}: {Message}",
                    response.Error, response.Message);
                return new SendMessageResult(false, Error: $"Zalo error: {response.Message}");
            }

            // EN: Add message to conversation / VI: Thêm tin nhắn vào cuộc hội thoại
            var message = conversation.AddMessage(
                MessageType.Text,
                request.Text,
                MessageDirection.Outgoing,
                isFromBot: request.IsFromBot,
                zaloMessageId: response.Data?.MessageId);

            _conversationRepository.Update(conversation);
            await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

            _logger.LogInformation(
                "EN: Message {MessageId} sent to {ZaloUserId}. VI: Tin nhắn {MessageId} đã gửi đến {ZaloUserId}",
                message.Id, conversation.ZaloUserId);

            return new SendMessageResult(
                true,
                MessageId: message.Id,
                ZaloMessageId: response.Data?.MessageId);
        }
        catch (ConversationClosedException ex)
        {
            _logger.LogWarning(ex,
                "EN: Cannot send to closed conversation. VI: Không thể gửi đến cuộc hội thoại đã đóng");
            return new SendMessageResult(false, Error: ex.Message);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex,
                "EN: Error sending message to {ZaloUserId}. VI: Lỗi gửi tin nhắn đến {ZaloUserId}",
                conversation.ZaloUserId);
            return new SendMessageResult(false, Error: ex.Message);
        }
    }
}
