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

namespace MktZaloService.API.Application.Commands.Webhook;

/// <summary>
/// EN: Handler for processing incoming Zalo webhook events.
/// VI: Handler để xử lý các sự kiện webhook đến từ Zalo.
/// </summary>
public class ProcessWebhookCommandHandler : IRequestHandler<ProcessWebhookCommand, ProcessWebhookResult>
{
    private readonly IZaloWebhookVerifier _webhookVerifier;
    private readonly ICustomerRepository _customerRepository;
    private readonly IConversationRepository _conversationRepository;
    private readonly IMediator _mediator;
    private readonly ILogger<ProcessWebhookCommandHandler> _logger;

    public ProcessWebhookCommandHandler(
        IZaloWebhookVerifier webhookVerifier,
        ICustomerRepository customerRepository,
        IConversationRepository conversationRepository,
        IMediator mediator,
        ILogger<ProcessWebhookCommandHandler> logger)
    {
        _webhookVerifier = webhookVerifier;
        _customerRepository = customerRepository;
        _conversationRepository = conversationRepository;
        _mediator = mediator;
        _logger = logger;
    }

    public async Task<ProcessWebhookResult> Handle(
        ProcessWebhookCommand request,
        CancellationToken cancellationToken)
    {
        // EN: Verify webhook signature / VI: Xác thực chữ ký webhook
        if (!_webhookVerifier.VerifySignature(request.RawBody, request.Signature))
        {
            _logger.LogWarning("EN: Invalid webhook signature. VI: Chữ ký webhook không hợp lệ");
            return new ProcessWebhookResult(false, Error: "Invalid signature");
        }

        var eventName = request.WebhookEvent.EventName;
        _logger.LogInformation(
            "EN: Processing webhook event {EventName}. VI: Đang xử lý sự kiện webhook {EventName}",
            eventName);

        try
        {
            return eventName switch
            {
                "user_send_text" => await HandleUserMessageAsync(request.WebhookEvent, cancellationToken),
                "user_send_image" => await HandleUserMessageAsync(request.WebhookEvent, cancellationToken),
                "user_send_file" => await HandleUserMessageAsync(request.WebhookEvent, cancellationToken),
                "user_send_sticker" => await HandleUserMessageAsync(request.WebhookEvent, cancellationToken),
                "follow" => await HandleFollowEventAsync(request.WebhookEvent, cancellationToken),
                "unfollow" => await HandleUnfollowEventAsync(request.WebhookEvent, cancellationToken),
                _ => new ProcessWebhookResult(true) // Acknowledge unknown events
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex,
                "EN: Error processing webhook {EventName}. VI: Lỗi xử lý webhook {EventName}",
                eventName);
            return new ProcessWebhookResult(false, Error: ex.Message);
        }
    }

    /// <summary>
    /// EN: Handle incoming user message.
    /// VI: Xử lý tin nhắn từ người dùng.
    /// </summary>
    private async Task<ProcessWebhookResult> HandleUserMessageAsync(
        Infrastructure.Zalo.Models.ZaloWebhookEvent webhookEvent,
        CancellationToken ct)
    {
        var senderId = webhookEvent.Sender?.Id;
        var messageText = webhookEvent.Message?.Text ?? string.Empty;
        var messageId = webhookEvent.Message?.MessageId;

        if (string.IsNullOrEmpty(senderId))
        {
            return new ProcessWebhookResult(false, Error: "Missing sender ID");
        }

        // EN: Get or create customer / VI: Lấy hoặc tạo khách hàng
        var customer = await _customerRepository.GetOrCreateAsync(
            senderId,
            displayName: $"Zalo User {senderId[..Math.Min(6, senderId.Length)]}",
            ct: ct);

        customer.RecordInteraction();
        customer.IncrementMessageCount();

        // EN: Get or create active conversation / VI: Lấy hoặc tạo cuộc hội thoại đang hoạt động
        var conversation = await _conversationRepository.FindActiveByZaloUserIdAsync(senderId, ct);

        if (conversation == null)
        {
            conversation = new Conversation(senderId, customer.Id);
            _conversationRepository.Add(conversation);
            customer.IncrementConversationCount();
        }

        // EN: Add incoming message / VI: Thêm tin nhắn đến
        var messageType = DetermineMessageType(webhookEvent.EventName);
        var message = conversation.AddMessage(
            messageType,
            messageText,
            MessageDirection.Incoming,
            isFromBot: false,
            zaloMessageId: messageId);

        // EN: Save changes / VI: Lưu thay đổi
        await _customerRepository.UnitOfWork.SaveEntitiesAsync(ct);

        // EN: Trigger chatbot rule matching (fire and forget via domain events)
        // VI: Kích hoạt khớp quy tắc chatbot (fire and forget qua domain events)
        _logger.LogInformation(
            "EN: Message {MessageId} added to conversation {ConversationId}. VI: Tin nhắn {MessageId} đã thêm vào cuộc hội thoại {ConversationId}",
            message.Id, conversation.Id);

        return new ProcessWebhookResult(true, MessageId: message.Id.ToString());
    }

    /// <summary>
    /// EN: Handle follow event (new follower).
    /// VI: Xử lý sự kiện theo dõi (người theo dõi mới).
    /// </summary>
    private async Task<ProcessWebhookResult> HandleFollowEventAsync(
        Infrastructure.Zalo.Models.ZaloWebhookEvent webhookEvent,
        CancellationToken ct)
    {
        var followerId = webhookEvent.Follower?.Id ?? webhookEvent.Sender?.Id;

        if (string.IsNullOrEmpty(followerId))
        {
            return new ProcessWebhookResult(false, Error: "Missing follower ID");
        }

        _logger.LogInformation(
            "EN: New follower {FollowerId}. VI: Người theo dõi mới {FollowerId}",
            followerId);

        // EN: Create customer record / VI: Tạo bản ghi khách hàng
        var customer = await _customerRepository.GetOrCreateAsync(
            followerId,
            displayName: $"Zalo User {followerId[..Math.Min(6, followerId.Length)]}",
            ct: ct);

        customer.MarkActive();
        await _customerRepository.UnitOfWork.SaveEntitiesAsync(ct);

        return new ProcessWebhookResult(true);
    }

    /// <summary>
    /// EN: Handle unfollow event.
    /// VI: Xử lý sự kiện hủy theo dõi.
    /// </summary>
    private async Task<ProcessWebhookResult> HandleUnfollowEventAsync(
        Infrastructure.Zalo.Models.ZaloWebhookEvent webhookEvent,
        CancellationToken ct)
    {
        var followerId = webhookEvent.Follower?.Id ?? webhookEvent.Sender?.Id;

        if (string.IsNullOrEmpty(followerId))
        {
            return new ProcessWebhookResult(false, Error: "Missing follower ID");
        }

        _logger.LogInformation(
            "EN: User unfollowed {FollowerId}. VI: Người dùng hủy theo dõi {FollowerId}",
            followerId);

        var customer = await _customerRepository.FindByZaloUserIdAsync(followerId, ct);
        if (customer != null)
        {
            customer.MarkInactive();
            await _customerRepository.UnitOfWork.SaveEntitiesAsync(ct);
        }

        return new ProcessWebhookResult(true);
    }

    private static MessageType DetermineMessageType(string? eventName)
    {
        return eventName switch
        {
            "user_send_text" => MessageType.Text,
            "user_send_image" => MessageType.Image,
            "user_send_sticker" => MessageType.Sticker,
            "user_send_file" => MessageType.Link,
            _ => MessageType.Text
        };
    }
}
