#nullable enable
using Baya.Application.Models.Booking;
using Baya.Application.Models.Common;
using Baya.Application.Models.Payments;
using Baya.Domain.Entities.Booking;

namespace Baya.Application.Contracts.Persistence;

/// <summary>
/// The pre-payment <c>booking_requests</c> aggregate. Writes load tracked, tenancy-scoped rows (the caller's
/// customer/nurse id) so an illegal cross-party access is a clean not-found, never a leak; reads project to
/// role-scoped DTOs. The expiry sweep selects stale rows through the covering indexes in bounded batches.
/// No money and no <c>bookings</c> row exist anywhere here.
/// </summary>
public interface IBookingRequestRepository
{
    Task AddAsync(BookingRequest request, CancellationToken cancellationToken);

    /// <summary>Tracked, customer-owned lookup for cancel. NULL if not owned/absent (existence not leaked).</summary>
    Task<BookingRequest?> GetTrackedForCustomerAsync(long id, long customerId, CancellationToken cancellationToken);

    /// <summary>Tracked, nurse-assigned lookup for accept/reject, with the <c>Customer</c> navigation loaded
    /// so the handler can notify the customer's user id. NULL if not the caller's/absent.</summary>
    Task<BookingRequest?> GetTrackedForNurseAsync(long id, long nurseId, CancellationToken cancellationToken);

    /// <summary>Tracked <c>pending_nurse_response</c> rows whose response deadline has passed (with
    /// <c>Customer</c> loaded), capped at <paramref name="batchSize"/> — one bounded page of the expiry sweep.</summary>
    Task<IReadOnlyList<BookingRequest>> GetStalePendingAsync(DateTime now, int batchSize, CancellationToken cancellationToken);

    /// <summary>Tracked <c>accepted_awaiting_payment</c> rows whose payment window has lapsed (with
    /// <c>Customer</c> loaded), capped at <paramref name="batchSize"/>.</summary>
    Task<IReadOnlyList<BookingRequest>> GetStaleAcceptedAsync(DateTime now, int batchSize, CancellationToken cancellationToken);

    /// <summary>The customer's own inbox — counterparty is the nurse (name + rating), actionable first.</summary>
    Task<PagedResult<BookingRequestListItemDto>> ListForCustomerAsync(long customerId, string? status, int page, int pageSize, CancellationToken cancellationToken);

    /// <summary>The nurse's inbox — counterparty is the patient; exposes stage-1 <c>customer_notes</c> only.</summary>
    Task<PagedResult<BookingRequestListItemDto>> ListForNurseAsync(long nurseId, string? status, int page, int pageSize, CancellationToken cancellationToken);

    /// <summary>Role-agnostic detail projection (carries both party ids for authorization + the full address
    /// for the customer/admin path). NULL when absent.</summary>
    Task<BookingRequestDetailProjection?> GetDetailAsync(long id, CancellationToken cancellationToken);

    /// <summary>Tracked lookup by id with <b>no</b> tenancy scope — the b9 conversion runs from a payment
    /// capture (a system/admin path), and flips the request to <c>converted</c> in the same unit of work.
    /// NULL when absent.</summary>
    Task<BookingRequest?> GetTrackedByIdAsync(long id, CancellationToken cancellationToken);

    /// <summary>Everything b9 needs to convert an <c>accepted_awaiting_payment</c> request into a booking in
    /// one projected read: ids + participant user ids, the engagement schedule, and the source data for the
    /// two frozen snapshots (variant + decrypted address). NULL when absent.</summary>
    Task<BookingConversionSource?> GetConversionSourceAsync(long id, CancellationToken cancellationToken);

    /// <summary>The facts b10's <c>InitiatePayment</c> needs to validate a card attempt (owning customer,
    /// status, frozen payment window, gross to charge). NULL when absent.</summary>
    Task<BookingPaymentContext?> GetPaymentContextAsync(long id, CancellationToken cancellationToken);

    /// <summary>Owner-scoped read for the checkout summary — the request's schedule/participant labels + the
    /// variant price/session-count needed to compute the money decomposition. NULL when the request is absent
    /// or not the caller's (existence not leaked).</summary>
    Task<CheckoutContext?> GetCheckoutContextAsync(long id, long customerId, CancellationToken cancellationToken);
}
