#nullable enable
using Baya.Domain.Entities.Payments;

namespace Baya.Application.Contracts.Persistence;

/// <summary>
/// The payments-core aggregate (gateways, transactions, webhook events, ledger). Writes load tracked rows;
/// balance reads project a signed aggregate over the append-only ledger. Money is IRR <c>long</c> throughout.
/// The DB uniques (Shaparak ref, succeeded-per-booking, the webhook idempotency key) are the authoritative
/// money-path backstops — the handlers rely on them, not just on a pre-check.
/// </summary>
public interface IPaymentRepository
{
    // ---- gateway selection ----
    /// <summary>The active gateway of <paramref name="type"/> with the lowest priority — config-driven
    /// selection so a cut-off provider is swapped without a code change. Null when none is configured.</summary>
    Task<long?> GetActiveGatewayIdAsync(string type, CancellationToken cancellationToken);

    Task AddGatewayAsync(PaymentGateway gateway, CancellationToken cancellationToken);

    // ---- transactions ----
    Task AddTransactionAsync(PaymentTransaction transaction, CancellationToken cancellationToken);

    /// <summary>Whether a booking created from this request already has a captured (succeeded) transaction —
    /// the initiate idempotency pre-check (the filtered succeeded-unique is the backstop).</summary>
    Task<bool> HasSucceededTransactionForRequestAsync(long bookingRequestId, CancellationToken cancellationToken);

    /// <summary>The tracked pending transaction carrying <paramref name="gatewayReferenceCode"/> — the webhook
    /// re-verify + confirm loads it to bind the capture. Null when absent.</summary>
    Task<PaymentTransaction?> GetTrackedTransactionByReferenceAsync(string gatewayReferenceCode, CancellationToken cancellationToken);

    Task<PaymentTransaction?> GetTrackedTransactionByIdAsync(long id, CancellationToken cancellationToken);

    // ---- webhook idempotency store ----
    /// <summary>The existing webhook event for this idempotency key, if any — a non-null result means a
    /// duplicate replay the handler no-ops on. Null on a brand-new event.</summary>
    Task<PaymentWebhookEvent?> GetWebhookEventByKeyAsync(string providerCode, string externalEventId, CancellationToken cancellationToken);

    Task AddWebhookEventAsync(PaymentWebhookEvent webhookEvent, CancellationToken cancellationToken);

    // ---- ledger ----
    /// <summary>Whether a posting group already exists for this payment transaction — makes the ledger post
    /// idempotent so a re-confirm never writes a second capture group.</summary>
    Task<bool> LedgerGroupExistsForTransactionAsync(long paymentTransactionId, CancellationToken cancellationToken);

    Task AddLedgerEntriesAsync(IEnumerable<LedgerEntry> entries, CancellationToken cancellationToken);

    /// <summary>The IRR balance currently owed a nurse — the signed sum over <c>nurse_payable</c> legs
    /// (credit adds, debit subtracts). Pure ledger projection, never a stored column. This is what b13 reads.</summary>
    Task<long> GetNursePayableBalanceAsync(long nurseId, CancellationToken cancellationToken);
}
