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

/// <summary>
/// The swappable PAYA/SATNA <b>bank payout rail</b> — the mocked stand-in for a real transferor (Jibit / Vandar /
/// Sadad payout API) that moves money out of the platform's registered source settlement account to each nurse's
/// verified Sheba. This is the one irreversible money-out step, so the seam carries an
/// <paramref name="idempotencyKey" /> and the whole submit is idempotent: a retried
/// <see cref="SubmitPayoutBatchAsync" /> for the same key never re-sends an already-<c>paid</c> instruction.
/// Handlers depend only on this contract; the concrete provider is a config-selected registration change, never
/// an <c>if (mock)</c> branch. <b>Every amount crossing this seam is IRR <c>long</c>.</b>
/// </summary>
public interface IBankTransferProvider
{
    /// <summary>Submits one <see cref="PayoutInstruction" /> per payout to the rail and returns a deterministic
    /// <c>externalBatchRef</c> plus a per-instruction result carrying the bank track id
    /// (<c>transfer_reference</c>) and status. The mock moves no money; a real transferor registers the batch
    /// against the source account and routes each PAYA/SATNA transfer.</summary>
    ValueTask<PayoutBatchSubmitResult> SubmitPayoutBatchAsync(
        long payoutBatchId,
        IReadOnlyList<PayoutInstruction> instructions,
        string idempotencyKey,
        CancellationToken cancellationToken = default);

    /// <summary>The reconciliation read — echoes the batch's settled status (the real callback flips
    /// <c>submitted → paid/failed</c>).</summary>
    ValueTask<BankTransferStatus> GetPayoutStatusAsync(string externalBatchRef, CancellationToken cancellationToken = default);
}

/// <summary>The settled state of a single transfer (or the batch echo). Forward-only on the payout row.</summary>
public enum BankTransferStatus
{
    /// <summary>The rail accepted the instruction (a track id was issued) but the transfer is not yet confirmed.</summary>
    Submitted,

    /// <summary>The transfer is confirmed — an irreversible IBAN movement.</summary>
    Paid,

    /// <summary>The rail rejected the transfer (closed day / insufficient provider balance / bad Sheba).</summary>
    Failed
}

/// <summary>The two Iranian interbank rails. Persisted/echoed as these stable codes; selection is by value
/// (SATNA for high-value rows above a config threshold, else PAYA).</summary>
public static class BankTransferMethod
{
    /// <summary>Batch ACH-style clearing — the default for ordinary-value payouts.</summary>
    public const string Paya = "paya";

    /// <summary>Real-time gross settlement — chosen for high-value rows above the SATNA threshold.</summary>
    public const string Satna = "satna";
}

/// <param name="PayoutId">The <c>nurse_payouts</c> row this instruction settles.</param>
/// <param name="Iban">The nurse's verified primary Sheba (the payout destination).</param>
/// <param name="AmountIrr">The net amount to transfer (IRR).</param>
/// <param name="Method">A <see cref="BankTransferMethod" /> code — PAYA or SATNA.</param>
public sealed record PayoutInstruction(long PayoutId, string Iban, long AmountIrr, string Method);

/// <param name="ExternalBatchRef">The rail's own batch reference, for reconciliation.</param>
/// <param name="Results">One result per submitted instruction.</param>
public sealed record PayoutBatchSubmitResult(string ExternalBatchRef, IReadOnlyList<PayoutInstructionResult> Results);

/// <param name="PayoutId">The payout this result belongs to.</param>
/// <param name="Status">The transfer outcome — drives the payout status machine.</param>
/// <param name="TransferReference">The bank track id, when the rail accepted it; null on failure.</param>
/// <param name="Method">The rail the transfer took (the honoured <see cref="PayoutInstruction.Method" />).</param>
/// <param name="FailureReason">Why the rail rejected it, when <see cref="Status" /> is
/// <see cref="BankTransferStatus.Failed" />.</param>
public sealed record PayoutInstructionResult(
    long PayoutId, BankTransferStatus Status, string? TransferReference, string Method, string? FailureReason);
