// EN: Handler for PayOrderCommand — routes to cash, card, or online payment flow.
// VI: Handler cho PayOrderCommand — điều hướng đến thanh toán tiền mặt, thẻ, hoặc trực tuyến.

using MediatR;
using OrderService.API.Hubs;
using OrderService.Domain.AggregatesModel.OrderAggregate;
using OrderService.Domain.Exceptions;
using OrderService.Infrastructure.ExternalServices;

namespace OrderService.API.Application.Commands;

/// <summary>
/// EN: Handler for processing payment based on payment method.
/// VI: Handler xử lý thanh toán dựa trên phương thức thanh toán.
/// </summary>
public class PayOrderCommandHandler : IRequestHandler<PayOrderCommand, PayOrderResult>
{
    private readonly IOrderRepository _orderRepository;
    private readonly IWalletServiceClient _walletServiceClient;
    private readonly IPosNotificationService _posNotificationService;
    private readonly ILogger<PayOrderCommandHandler> _logger;

    public PayOrderCommandHandler(
        IOrderRepository orderRepository,
        IWalletServiceClient walletServiceClient,
        IPosNotificationService posNotificationService,
        ILogger<PayOrderCommandHandler> logger)
    {
        _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
        _walletServiceClient = walletServiceClient ?? throw new ArgumentNullException(nameof(walletServiceClient));
        _posNotificationService = posNotificationService ?? throw new ArgumentNullException(nameof(posNotificationService));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public async Task<PayOrderResult> Handle(
        PayOrderCommand request,
        CancellationToken cancellationToken)
    {
        _logger.LogInformation(
            "EN: Processing {PaymentMethod} payment for order {OrderId} / VI: Xử lý thanh toán {PaymentMethod} cho order {OrderId}",
            request.PaymentMethod, request.OrderId);

        // EN: Load order / VI: Load order
        var order = await _orderRepository.GetByIdAsync(request.OrderId, cancellationToken);
        if (order == null)
        {
            throw new DomainException($"Order not found: {request.OrderId}");
        }

        // EN: Verify shop ownership / VI: Xác minh quyền sở hữu shop
        if (order.ShopId != request.ShopId)
        {
            throw new DomainException("Order does not belong to this shop");
        }

        var method = request.PaymentMethod.ToLowerInvariant();

        return method switch
        {
            "cash" => await ProcessCashPayment(order, request, cancellationToken),
            "card" => await ProcessCardPayment(order, request, cancellationToken),
            "vnpay" or "momo" => await ProcessOnlinePayment(order, request, method, cancellationToken),
            // EN: Default — treat "qr" and "transfer" as immediate like card (POS-confirmed)
            // VI: Mặc định — xử lý "qr" và "transfer" như thẻ (POS xác nhận)
            _ => await ProcessCardPayment(order, request, cancellationToken),
        };
    }

    /// <summary>
    /// EN: Process cash payment — instant, calculate change.
    /// VI: Xử lý thanh toán tiền mặt — ngay lập tức, tính tiền thối.
    /// </summary>
    private async Task<PayOrderResult> ProcessCashPayment(
        Order order,
        PayOrderCommand request,
        CancellationToken cancellationToken)
    {
        var amountTendered = request.AmountTendered ?? order.TotalAmount;

        if (amountTendered < order.TotalAmount)
        {
            return new PayOrderResult(
                false, order.Status.Name, null, null, null,
                $"Insufficient cash: tendered {amountTendered}, required {order.TotalAmount}");
        }

        var transactionId = $"CASH-{DateTime.UtcNow:yyyyMMddHHmmss}-{Guid.NewGuid().ToString("N")[..8].ToUpper()}";
        var changeAmount = amountTendered - order.TotalAmount;

        // EN: Mark as paid → processing → completed (POS direct sale — no kitchen/prep step)
        // VI: Đánh dấu đã thanh toán → đang xử lý → hoàn thành (POS bán trực tiếp — không qua bếp)
        order.MarkAsPaid("cash", transactionId, amountTendered);
        order.MarkAsProcessing();
        order.MarkAsCompleted();

        await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation(
            "EN: Cash payment completed for order {OrderId}, change: {Change} / VI: Thanh toán tiền mặt hoàn tất cho order {OrderId}, tiền thối: {Change}",
            order.Id, changeAmount);

        // EN: Send real-time payment notification / VI: Gửi thông báo thanh toán real-time
        await SendPaymentNotificationAsync(order, "cash", cancellationToken);

        return new PayOrderResult(true, order.Status.Name, null, changeAmount, transactionId, null);
    }

    /// <summary>
    /// EN: Process card payment — instant (terminal handles actual charge).
    /// VI: Xử lý thanh toán thẻ — ngay lập tức (terminal xử lý giao dịch thực).
    /// </summary>
    private async Task<PayOrderResult> ProcessCardPayment(
        Order order,
        PayOrderCommand request,
        CancellationToken cancellationToken)
    {
        var transactionId = $"CARD-{DateTime.UtcNow:yyyyMMddHHmmss}-{Guid.NewGuid().ToString("N")[..8].ToUpper()}";

        // EN: Mark as paid → processing → completed (POS direct sale — card/qr/transfer confirmed at terminal)
        // VI: Đánh dấu đã thanh toán → đang xử lý → hoàn thành (POS bán trực tiếp — thẻ/QR/CK xác nhận tại máy)
        order.MarkAsPaid(request.PaymentMethod.ToLowerInvariant(), transactionId);
        order.MarkAsProcessing();
        order.MarkAsCompleted();

        await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation(
            "EN: Card payment completed for order {OrderId} / VI: Thanh toán thẻ hoàn tất cho order {OrderId}",
            order.Id);

        // EN: Send real-time payment notification / VI: Gửi thông báo thanh toán real-time
        await SendPaymentNotificationAsync(order, request.PaymentMethod.ToLowerInvariant(), cancellationToken);

        return new PayOrderResult(true, order.Status.Name, null, null, transactionId, null);
    }

    /// <summary>
    /// EN: Process online payment (VNPay/Momo) — creates payment via wallet-service, returns redirect URL.
    /// VI: Xử lý thanh toán trực tuyến (VNPay/Momo) — tạo payment qua wallet-service, trả về URL redirect.
    /// </summary>
    private async Task<PayOrderResult> ProcessOnlinePayment(
        Order order,
        PayOrderCommand request,
        string gateway,
        CancellationToken cancellationToken)
    {
        try
        {
            var paymentResponse = await _walletServiceClient.CreatePaymentAsync(
                order.Id,
                order.TotalAmount,
                gateway,
                request.ReturnUrl ?? "",
                request.IpAddress ?? "127.0.0.1",
                cancellationToken);

            if (paymentResponse == null || string.IsNullOrEmpty(paymentResponse.PaymentUrl))
            {
                return new PayOrderResult(
                    false, order.Status.Name, null, null, null,
                    "Failed to create online payment / Không thể tạo thanh toán trực tuyến");
            }

            // EN: Mark order as payment pending / VI: Đánh dấu order chờ thanh toán
            order.MarkAsPaymentPending(gateway, paymentResponse.TransactionId);

            await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

            _logger.LogInformation(
                "EN: Online payment initiated for order {OrderId} via {Gateway}, txn: {TxnId} / VI: Thanh toán trực tuyến đã khởi tạo cho order {OrderId} qua {Gateway}, giao dịch: {TxnId}",
                order.Id, gateway, paymentResponse.TransactionId);

            return new PayOrderResult(
                true, order.Status.Name, paymentResponse.PaymentUrl, null, paymentResponse.TransactionId, null);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex,
                "EN: Failed to create online payment for order {OrderId} / VI: Không thể tạo thanh toán trực tuyến cho order {OrderId}",
                order.Id);

            return new PayOrderResult(
                false, order.Status.Name, null, null, null,
                $"Payment gateway error: {ex.Message}");
        }
    }

    /// <summary>
    /// EN: Send real-time payment notification to POS/KDS clients.
    /// VI: Gửi thông báo thanh toán real-time đến POS/KDS clients.
    /// </summary>
    private async Task SendPaymentNotificationAsync(
        Order order,
        string paymentMethod,
        CancellationToken cancellationToken)
    {
        try
        {
            var payment = new PaymentNotificationDto(
                OrderId: order.Id,
                Amount: order.TotalAmount,
                Method: paymentMethod,
                Status: "Completed");

            await _posNotificationService.NotifyPaymentCompletedAsync(
                order.ShopId, payment, cancellationToken);

            await _posNotificationService.NotifyOrderStatusChangedAsync(
                order.ShopId, order.Id, "Validated", order.Status.Name, cancellationToken);
        }
        catch (Exception ex)
        {
            // EN: Don't fail the command if notification fails
            // VI: Không fail command nếu notification thất bại
            _logger.LogWarning(ex,
                "EN: Failed to send payment notification for order {OrderId} / " +
                "VI: Gửi thông báo thanh toán thất bại cho order {OrderId}",
                order.Id);
        }
    }
}
