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

namespace Baya.Application.Contracts.Persistence;

/// <summary>
/// The BNPL aggregate — one <c>bnpl_transactions</c> row per order (1:1 with its <c>payment_transaction</c>).
/// Writes load tracked rows; reads project to DTOs. The ledger legs themselves are appended through
/// <see cref="IPaymentRepository.AddLedgerEntriesAsync"/> (b10's helper); this repo owns only the BNPL row, the
/// order-context read, and the settle-ledger idempotency probe. Money is IRR <c>long</c>. The
/// <c>UNIQUE(payment_transaction_id)</c> guard is the structural one-BNPL-row-per-order backstop.
/// </summary>
public interface IBnplRepository
{
    /// <summary>Everything eligibility/initiate need for a booking request (owner + mobile + status + gross).
    /// Null when the request does not exist.</summary>
    Task<BnplOrderContext?> GetOrderContextAsync(long bookingRequestId, CancellationToken cancellationToken);

    Task AddAsync(BnplTransaction transaction, CancellationToken cancellationToken);

    /// <summary>The tracked BNPL row for a payment transaction — the 1:1 lookup eligibility/initiate upsert on.
    /// Null when none exists yet.</summary>
    Task<BnplTransaction?> GetTrackedByPaymentTransactionIdAsync(long paymentTransactionId, CancellationToken cancellationToken);

    Task<BnplTransaction?> GetTrackedByIdAsync(long id, CancellationToken cancellationToken);

    /// <summary>The tracked BNPL row for a booking request (via its payment transaction) — the find-or-create
    /// anchor eligibility and initiate share so a request has at most one BNPL order. Null when none exists.</summary>
    Task<BnplTransaction?> GetTrackedByBookingRequestIdAsync(long bookingRequestId, CancellationToken cancellationToken);

    /// <summary>The tracked BNPL row carrying <paramref name="externalPaymentToken"/> — the callback dispatch
    /// resolves the order from the token in the payload. Null when absent.</summary>
    Task<BnplTransaction?> GetTrackedByTokenAsync(string externalPaymentToken, CancellationToken cancellationToken);

    /// <summary>Whether the balanced settle group already exists for this BNPL row — makes the settle post
    /// idempotent so a replayed settle never writes a second net-of-fee group.</summary>
    Task<bool> SettleLedgerExistsAsync(long bnplTransactionId, CancellationToken cancellationToken);

    /// <summary>The BNPL order view + the owning customer's user id for tenancy, and the linked refund's ETA
    /// when reverted. Null when absent.</summary>
    Task<BnplOrderStatusProjection?> GetStatusAsync(long id, CancellationToken cancellationToken);

    /// <summary>The BNPL order for a booking request (the id the return-poll surface holds), latest first, with the
    /// owning customer's user id for tenancy. Null when the request has no BNPL order.</summary>
    Task<BnplOrderStatusProjection?> GetStatusByRequestAsync(long bookingRequestId, CancellationToken cancellationToken);
}
