namespace WalletService.API.Application.Commands.Payments;

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

/// <summary>
/// EN: Handler for CreatePaymentCommand. Creates a payment entity and initiates payment via gateway.
/// VI: Handler cho CreatePaymentCommand. Tao entity thanh toan va bat dau thanh toan qua cong thanh toan.
/// </summary>
public class CreatePaymentCommandHandler : IRequestHandler<CreatePaymentCommand, CreatePaymentResult>
{
    private readonly IPaymentRepository _paymentRepository;
    private readonly IEnumerable<IPaymentGateway> _paymentGateways;
    private readonly ILogger<CreatePaymentCommandHandler> _logger;

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

    public async Task<CreatePaymentResult> Handle(
        CreatePaymentCommand request,
        CancellationToken cancellationToken)
    {
        _logger.LogInformation(
            "EN: Creating payment for order {OrderId}, gateway {GatewayName} / " +
            "VI: Tao thanh toan cho don hang {OrderId}, cong thanh toan {GatewayName}",
            request.OrderId, request.GatewayName);

        // EN: Find the requested payment gateway
        // VI: Tim cong thanh toan duoc yeu cau
        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: Create payment entity
        // VI: Tao entity thanh toan
        var payment = new Payment(
            request.OrderId,
            request.Amount,
            request.Currency,
            gateway.GatewayName);

        // EN: Call gateway to create payment
        // VI: Goi cong thanh toan de tao thanh toan
        var paymentRequest = new PaymentRequest(
            request.OrderId,
            request.Amount,
            request.Currency,
            $"Payment for order {request.OrderId}",
            request.ReturnUrl,
            request.IpAddress);

        var gatewayResult = await gateway.CreatePaymentAsync(paymentRequest, cancellationToken);

        if (gatewayResult.Success)
        {
            // EN: Mark as processing with payment URL
            // VI: Danh dau dang xu ly voi URL thanh toan
            payment.MarkAsProcessing(gatewayResult.PaymentUrl, gatewayResult.TransactionId);
        }
        else
        {
            // EN: Mark as failed
            // VI: Danh dau that bai
            payment.Fail(gatewayResult.ErrorCode, gatewayResult.ErrorMessage);
        }

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

        _logger.LogInformation(
            "EN: Payment {PaymentId} created for order {OrderId}, status: {Status} / " +
            "VI: Thanh toan {PaymentId} da tao cho don hang {OrderId}, trang thai: {Status}",
            payment.Id, request.OrderId, payment.Status.Name);

        return new CreatePaymentResult(
            payment.Id,
            payment.OrderId,
            payment.Amount,
            payment.Currency,
            payment.GatewayName,
            payment.Status.Name,
            payment.PaymentUrl,
            payment.CreatedAt);
    }
}
