namespace WalletService.API.Application.Commands.Payments;

using MediatR;
using WalletService.Domain.AggregatesModel.PaymentAggregate;
using WalletService.Domain.Exceptions;

/// <summary>
/// EN: Handler for ProcessPaymentCallbackCommand. Validates gateway callback and updates payment status.
/// VI: Handler cho ProcessPaymentCallbackCommand. Xac thuc callback cong thanh toan va cap nhat trang thai.
/// </summary>
public class ProcessPaymentCallbackCommandHandler
    : IRequestHandler<ProcessPaymentCallbackCommand, ProcessPaymentCallbackResult>
{
    private readonly IPaymentRepository _paymentRepository;
    private readonly IEnumerable<IPaymentGateway> _paymentGateways;
    private readonly ILogger<ProcessPaymentCallbackCommandHandler> _logger;

    public ProcessPaymentCallbackCommandHandler(
        IPaymentRepository paymentRepository,
        IEnumerable<IPaymentGateway> paymentGateways,
        ILogger<ProcessPaymentCallbackCommandHandler> logger)
    {
        _paymentRepository = paymentRepository;
        _paymentGateways = paymentGateways;
        _logger = logger;
    }

    public async Task<ProcessPaymentCallbackResult> Handle(
        ProcessPaymentCallbackCommand request,
        CancellationToken cancellationToken)
    {
        _logger.LogInformation(
            "EN: Processing payment callback from gateway {GatewayName} / " +
            "VI: Xu ly callback thanh toan tu cong thanh toan {GatewayName}",
            request.GatewayName);

        // EN: Find the payment gateway
        // VI: Tim cong thanh toan
        var gateway = _paymentGateways.FirstOrDefault(
            g => g.GatewayName.Equals(request.GatewayName, StringComparison.OrdinalIgnoreCase))
            ?? throw new WalletDomainException(
                $"Payment gateway '{request.GatewayName}' is not supported / " +
                $"Cong thanh toan '{request.GatewayName}' khong duoc ho tro");

        // EN: Validate callback hash
        // VI: Xac thuc hash callback
        request.Parameters.TryGetValue("vnp_SecureHash", out var secureHash);
        if (!gateway.ValidateCallback(request.Parameters, secureHash ?? string.Empty))
        {
            _logger.LogWarning(
                "EN: Invalid callback signature from {GatewayName} / " +
                "VI: Chu ky callback khong hop le tu {GatewayName}",
                request.GatewayName);

            return new ProcessPaymentCallbackResult(
                Success: false,
                PaymentId: null,
                OrderId: null,
                Status: "InvalidSignature",
                ErrorMessage: "Invalid callback signature / Chu ky callback khong hop le");
        }

        // EN: Find the payment by transaction reference
        // VI: Tim thanh toan theo tham chieu giao dich
        request.Parameters.TryGetValue("vnp_TxnRef", out var txnRef);
        if (!Guid.TryParse(txnRef, out var orderId))
        {
            return new ProcessPaymentCallbackResult(
                Success: false,
                PaymentId: null,
                OrderId: null,
                Status: "InvalidReference",
                ErrorMessage: "Invalid transaction reference / Tham chieu giao dich khong hop le");
        }

        var payment = await _paymentRepository.GetByOrderIdAsync(orderId);
        if (payment == null)
        {
            _logger.LogWarning(
                "EN: Payment not found for order {OrderId} / " +
                "VI: Khong tim thay thanh toan cho don hang {OrderId}",
                orderId);

            return new ProcessPaymentCallbackResult(
                Success: false,
                PaymentId: null,
                OrderId: orderId,
                Status: "NotFound",
                ErrorMessage: "Payment not found / Khong tim thay thanh toan");
        }

        // EN: Process the callback based on response code
        // VI: Xu ly callback dua tren ma phan hoi
        request.Parameters.TryGetValue("vnp_ResponseCode", out var responseCode);
        responseCode ??= "99";
        request.Parameters.TryGetValue("vnp_TransactionNo", out var transactionNo);
        transactionNo ??= string.Empty;

        if (responseCode == "00")
        {
            // EN: Payment successful
            // VI: Thanh toan thanh cong
            payment.Complete(transactionNo);

            _logger.LogInformation(
                "EN: Payment {PaymentId} completed for order {OrderId} / " +
                "VI: Thanh toan {PaymentId} hoan thanh cho don hang {OrderId}",
                payment.Id, orderId);
        }
        else
        {
            // EN: Payment failed
            // VI: Thanh toan that bai
            request.Parameters.TryGetValue("vnp_OrderInfo", out var errorMessage);
            errorMessage ??= "Payment failed";
            payment.Fail(responseCode, errorMessage);

            _logger.LogWarning(
                "EN: Payment {PaymentId} failed for order {OrderId}, code: {ErrorCode} / " +
                "VI: Thanh toan {PaymentId} that bai cho don hang {OrderId}, ma: {ErrorCode}",
                payment.Id, orderId, responseCode);
        }

        _paymentRepository.Update(payment);
        await _paymentRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        return new ProcessPaymentCallbackResult(
            Success: responseCode == "00",
            PaymentId: payment.Id,
            OrderId: orderId,
            Status: payment.Status.Name,
            ErrorMessage: responseCode == "00" ? null : $"VN Pay response code: {responseCode}");
    }
}
