#nullable enable
namespace Baya.Application.Contracts.Payments;

/// <summary>
/// The swappable card-PSP acquirer seam (ZarinPal / Sadad / Vandar / Jibit …). Handlers depend only on this
/// contract; the concrete provider is selected from <c>payment_gateways</c> config so a cut-off provider is
/// swapped without a code change. <b>Every amount crossing this seam is IRR <c>long</c></b> — Toman conversion
/// happens only inside a real adapter at its boundary, never here.
/// </summary>
public interface IPaymentProvider
{
    /// <summary>Starts an IPG session and returns the redirect URL plus a deterministic gateway reference to
    /// persist on the pending transaction (honouring its filtered unique). <paramref name="idempotencyKey"/>
    /// makes a retried initiate return the same reference rather than opening a second session.</summary>
    ValueTask<PaymentInitResult> InitPaymentAsync(long bookingRequestId, long amountIrr, string idempotencyKey, CancellationToken cancellationToken = default);

    /// <summary>The mandatory server-side re-check (<b>never trust a callback alone</b>): re-verifies the
    /// amount + reference against the gateway before a success callback is allowed to confirm.</summary>
    ValueTask<PaymentVerifyResult> VerifyAsync(string gatewayReferenceCode, long expectedAmountIrr, CancellationToken cancellationToken = default);

    /// <summary>Reverses a captured payment (partial or full). The <paramref name="idempotencyKey"/> makes a
    /// retried refund a no-op rather than a double reversal (b11 refunds carry the booking+refund key).</summary>
    ValueTask<PaymentRefundResult> RefundAsync(string gatewayReferenceCode, long amountIrr, string idempotencyKey, CancellationToken cancellationToken = default);
}

/// <summary>The outcome verb of a provider verify/refund — mirrors the wire <c>payment</c> status codes.</summary>
public enum PaymentProviderStatus
{
    Pending,
    Succeeded,
    Failed
}

/// <param name="RedirectUrl">Where the client is sent to complete the card payment.</param>
/// <param name="GatewayReferenceCode">The deterministic reference persisted on the pending transaction.</param>
public sealed record PaymentInitResult(string RedirectUrl, string GatewayReferenceCode);

/// <param name="Status">The re-verified outcome — only <see cref="PaymentProviderStatus.Succeeded"/> confirms.</param>
/// <param name="AmountIrr">The amount the gateway reports, re-checked against the stored transaction.</param>
public sealed record PaymentVerifyResult(PaymentProviderStatus Status, long AmountIrr);

/// <param name="Status">Whether the reversal was accepted by the gateway.</param>
/// <param name="GatewayRefundReference">The provider's refund reference, when issued.</param>
public sealed record PaymentRefundResult(PaymentProviderStatus Status, string? GatewayRefundReference);
