using SIGCM2.Domain.Pricing.ChargeableChars;

namespace SIGCM2.Application.Abstractions.Persistence;

/// <summary>
/// PRC-001 — Write + query access to dbo.ChargeableCharConfig.
/// Implemented by ChargeableCharConfigRepository (Dapper) in Infrastructure.
///
/// InsertWithCloseAsync: invokes usp_ChargeableCharConfig_InsertWithClose which atomically
/// closes any active row for (ProductTypeId, Symbol) and inserts the new row.
///
/// GetActiveForProductTypeAsync: invokes usp_ChargeableCharConfig_GetActiveForProductType which
/// returns both per-ProductType rows AND global (ProductTypeId IS NULL) rows for the given asOfDate.
/// The Application service applies the per-ProductType > global priority rule.
/// </summary>
public interface IChargeableCharConfigRepository
{
    /// <summary>
    /// Invokes usp_ChargeableCharConfig_InsertWithClose inside the ambient TransactionScope.
    /// Closes any active row matching (ProductTypeId, Symbol) and inserts a new one.
    /// Returns the Id of the newly inserted row.
    /// Throws:
    ///   - ChargeableCharConfigForwardOnlyException on SQL THROW 50409
    ///   - ChargeableCharConfigInvalidException on SQL THROW 50404 (not-found guard)
    /// </summary>
    Task<long> InsertWithCloseAsync(
        long? productTypeId,
        string symbol,
        string category,
        decimal price,
        DateOnly validFrom,
        CancellationToken ct = default);

    /// <summary>
    /// Returns all active rows whose [ValidFrom, ValidTo] window covers the given asOfDate
    /// for the specified ProductType, including global rows (ProductTypeId IS NULL).
    /// The SP returns both per-ProductType AND global rows — callers apply priority.
    /// </summary>
    Task<IReadOnlyList<ChargeableCharConfig>> GetActiveForProductTypeAsync(
        long productTypeId,
        DateOnly asOfDate,
        CancellationToken ct = default);

    /// <summary>
    /// Returns paginated rows filtered by ProductTypeId and IsActive.
    /// Skip = (page - 1) * pageSize computed by the caller.
    /// </summary>
    Task<IReadOnlyList<ChargeableCharConfig>> ListAsync(
        long? productTypeId,
        bool activeOnly,
        int skip,
        int take,
        CancellationToken ct = default);

    /// <summary>
    /// Returns total row count for the given filters (used for pagination metadata).
    /// </summary>
    Task<int> CountAsync(
        long? productTypeId,
        bool activeOnly,
        CancellationToken ct = default);

    /// <summary>
    /// Returns the row with the given Id, or null if not found.
    /// </summary>
    Task<ChargeableCharConfig?> GetByIdAsync(
        long id,
        CancellationToken ct = default);

    /// <summary>
    /// Deactivates the row with the given Id by setting IsActive = false and ValidTo = today.
    /// Idempotent: no-op if already inactive.
    /// Called inside the ambient TransactionScope of the handler.
    /// </summary>
    Task DeactivateAsync(
        long id,
        DateOnly today,
        CancellationToken ct = default);

    /// <summary>
    /// Invokes usp_ChargeableCharConfig_ReactivateWithGuard.
    /// Guard rules (enforced by SP):
    ///   50410 → target row is already active → ChargeableCharConfigReactivationNotAllowedException(ALREADY_ACTIVE)
    ///   50411 → a vigente active row exists for (ProductTypeId, Symbol) → ChargeableCharConfigReactivationNotAllowedException(VIGENTE_EXISTS)
    ///   50412 → posterior rows exist after target row → ChargeableCharConfigReactivationNotAllowedException(POSTERIOR_ROWS_EXIST)
    ///   50404 → row not found → ChargeableCharConfigInvalidException
    /// On success: re-opens the row (IsActive=true, ValidTo=NULL) and returns the reactivated entity.
    /// </summary>
    Task<ChargeableCharConfig> ReactivateAsync(
        long id,
        CancellationToken ct = default);

    /// <summary>
    /// Physically deletes the row with the given Id from dbo.ChargeableCharConfig (current state).
    /// NOTE: Since SYSTEM_VERSIONING is ON, SQL Server moves the row to the history table with
    /// SysEndTime set to the delete time. The row disappears from all current-state queries but
    /// remains queryable via FOR SYSTEM_TIME. Temporal audit trail is preserved.
    /// Future guard for "used in invoicing" is deferred to FAC-001 followup issue.
    /// Throws KeyNotFoundException if the row does not exist.
    /// </summary>
    Task DeleteAsync(
        long id,
        CancellationToken ct = default);
}
