#nullable enable
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Bnpl;
using Baya.Domain.Entities.Bnpl;
using Baya.Domain.Entities.Payments;

namespace Baya.Application.Features.Bnpl;

/// <summary>
/// The single find-or-create for a BNPL order's skeleton — the pending <c>payment_transaction</c> (bnpl gateway)
/// plus the 1:1 <c>bnpl_transactions</c> row — shared by eligibility and initiate so a booking request has at
/// most one BNPL order. The <c>UNIQUE(payment_transaction_id)</c> guard is the structural backstop; this helper
/// is the friendly pre-check. It commits the two rows (the payment transaction id must exist before the BNPL FK)
/// and returns the tracked BNPL row; the caller owns the provider call, the state transition and any lock.
/// </summary>
internal static class BnplOrderInitializer
{
    public static async Task<BnplTransaction> EnsureAsync(
        IUnitOfWork unitOfWork,
        BnplOrderContext context,
        long gatewayId,
        string providerCode,
        string merchantOfRecord,
        long orderAmountIrr,
        string currency,
        string? ipAddress,
        CancellationToken cancellationToken)
    {
        var existing = await unitOfWork.BnplRepository.GetTrackedByBookingRequestIdAsync(context.RequestId, cancellationToken);
        if (existing is not null)
            return existing;

        // A BNPL order is a card payment landing net-of-fee, so it rides the same payment_transactions rail
        // (booking_id null until settle binds it, exactly like the card path).
        var transaction = new PaymentTransaction
        {
            BookingRequestId = context.RequestId,
            CustomerId = context.CustomerId,
            GatewayId = gatewayId,
            Amount = orderAmountIrr,
            Currency = "IRR",
            IsInstallment = true,
            IpAddress = ipAddress
        };
        await unitOfWork.PaymentRepository.AddTransactionAsync(transaction, cancellationToken);
        await unitOfWork.CommitAsync();

        var bnpl = new BnplTransaction
        {
            PaymentTransactionId = transaction.Id,
            ProviderCode = providerCode,
            MerchantOfRecord = merchantOfRecord,
            OrderAmountIrr = orderAmountIrr,
            Currency = currency,
            EligibilityStatus = null
        };
        await unitOfWork.BnplRepository.AddAsync(bnpl, cancellationToken);
        await unitOfWork.CommitAsync();

        return bnpl;
    }
}
