/**
 * kestrel.markets/protocol — OfferTerms, the commercial-terms VOCABULARY carried on
 * an Offer (PLAT-ADR-0028 slice A1, owner-approved protocol-first split 2026-07-15).
 *
 * SHAPES ONLY. This module states the closed set of ways an Offer may be priced —
 * one-shot, recurring, minimum-commitment, included-credits, committed-use-discount —
 * as pure nouns/enums. It carries NO semantics: no billing, proration, renewal-clock,
 * or credit-burn logic lives here. Recurring-Envelope SEMANTICS are explicitly OUT of
 * scope (platform M2). Like the rest of `src/protocol/**` this file imports NOTHING and
 * pulls in no runtime (asserted by tests/protocol.boundary.test.ts).
 */

/* ─────────────────────────────── offer terms ───────────────────────────────── */

/**
 * Billing/commitment cadence for recurring and minimum-commitment terms. A closed,
 * calendar-grained vocabulary; opaque to the protocol (no scheduling semantics here).
 */
export type BillingPeriod = "day" | "week" | "month" | "quarter" | "year";

/** Whether a recurring term rolls over on its own or requires a fresh acceptance. */
export type RenewalMode = "auto" | "manual";

/**
 * The commercial terms an Offer prices, discriminated on `kind` (same `kind` idiom as
 * {@link import("./index.ts").SettlementMethod}). Additive union — a `PaymentRequired`
 * may list several as plural alternatives (`offers[]`). No member carries execution
 * semantics; every amount is a bare settlement number (asset lives on the Offer).
 */
export type OfferTerms =
  /** A single up-front purchase; no recurring or committed terms. */
  | { readonly kind: "one_shot" }
  /** A subscription billed each `term`, rolling over per `renewal`. */
  | { readonly kind: "recurring"; readonly term: BillingPeriod; readonly renewal: RenewalMode }
  /** A floor the buyer commits to spend (`amount`) each `period`. */
  | { readonly kind: "min_commit"; readonly amount: number; readonly period: BillingPeriod }
  /** A bundle of prepaid `amount` credits, void after `expiry` (ISO-8601). */
  | { readonly kind: "included_credits"; readonly amount: number; readonly expiry: string }
  /** A discount (`discountBps`, basis points) for committing to spend `amount` each `period`. */
  | {
      readonly kind: "committed_use_discount";
      readonly amount: number;
      readonly period: BillingPeriod;
      readonly discountBps: number;
    };

/** The discriminant of every {@link OfferTerms} member. */
export type OfferTermsKind = OfferTerms["kind"];

/**
 * Runtime tuple of every {@link OfferTermsKind}. Same both-ways closed-vocabulary guard
 * as {@link import("./index.ts").SCOPES}: a `.kind` added to (or removed from) the union
 * without editing this tuple fails the `satisfies`/exhaustiveness check below at compile
 * time. The platform's OpenAPI conformance check reads these contents.
 */
export const OFFER_TERMS_KINDS = [
  "one_shot",
  "recurring",
  "min_commit",
  "included_credits",
  "committed_use_discount",
] as const satisfies readonly OfferTermsKind[];
/** Reverse-exhaustiveness proof: any `OfferTermsKind` omitted from {@link OFFER_TERMS_KINDS} makes `_Missing`'s default non-`never`, which violates its `never` constraint and fails to compile. */
type _OfferTermsKindsExhaustive<_Missing extends never = Exclude<OfferTermsKind, (typeof OFFER_TERMS_KINDS)[number]>> = true;
