/**
 * # session/sizing — the cockpit's bounded-risk sizing + budget envelopes
 *
 * The two pure projections the Simulate driver ({@link import("./simulate.ts")}) layers onto the wake
 * kernel so a model sizes WITHIN the bounded-risk envelope instead of into a silent fire-time clamp:
 *  - {@link sizingHeadroomOf} — the MAX fillable size the remaining-R budget admits for the exec
 *    instrument, charged at the FULL COST BASIS (ADR-0017: equity `spot × mult`, option `premium × mult`);
 *  - {@link budgetEnvelopeOf} — the remaining-R fraction + the nested plan ⊆ book ⊆ owner envelopes,
 *    carrying the optional {@link SizingHeadroom} when the caller can source the exec price.
 *
 * PURE: derivations of the injected budget + price, no wall clock / RNG. Both fail closed — an
 * unbuildable basis (no live price, a non-finite premium) yields a `null` cap + a note of the cost-basis
 * rule, never a fabricated per-leg number.
 */

import type { Budget, BudgetEnvelope, SizingHeadroom } from "../frame/types.ts";

/** The **sizing headroom** (kestrel-m9i.32) — the MAX fillable size the remaining-R budget admits for
 * the exec instrument, so a model sizes WITHIN the bounded-risk envelope instead of into a SILENT
 * fire-time clamp. Bounded risk is the FULL COST BASIS (ADR-0017): equity charges `qty × spot × mult`
 * (mult 1), an option `qty × premium × mult` — so `maxUnits = floor(remainingUsd / basisPerUnit)`.
 *
 * Equity/spot (`multiplier === 1`): the per-share basis IS the spot; when spot is a live finite price
 * the cue is concrete. Option (`multiplier !== 1`): the basis is `premium × mult`; when a near-money
 * `optionPremium` is supplied the cue is concrete, otherwise the basis is unbuildable — the model
 * still gets the remaining-$ ceiling + a note of the cost-basis rule (never a fabricated per-leg cap).
 * PURE: a derivation of the injected budget + price, no wall clock / RNG. */
export function sizingHeadroomOf(args: {
  readonly instrument: string;
  readonly remainingUsd: number | null;
  readonly spot: number | null;
  readonly multiplier: number;
  readonly optionPremium?: number | null;
}): SizingHeadroom {
  const { instrument, remainingUsd, spot, multiplier } = args;
  const isOption = multiplier !== 1;
  const unit: SizingHeadroom["unit"] = isOption ? "contracts" : "shares";
  // The per-unit cost basis the clamp charges: equity = spot × mult (mult 1); option = premium × mult.
  const premium = isOption ? args.optionPremium ?? null : spot;
  const basisPerUnit =
    premium !== null && premium !== undefined && Number.isFinite(premium) && premium > 0 ? premium * multiplier : null;
  const rem = remainingUsd !== null && remainingUsd !== undefined && Number.isFinite(remainingUsd) ? remainingUsd : null;
  const maxUnits = basisPerUnit !== null && rem !== null ? Math.floor(rem / basisPerUnit) : null;
  const note =
    isOption && basisPerUnit === null
      ? "option basis = premium × mult (ADR-0017); size ≤ remaining/(premium × mult)"
      : undefined;
  return {
    instrument,
    unit,
    basisPerUnit,
    maxUnits,
    remainingUsd: rem,
    ...(note !== undefined ? { note } : {}),
  };
}

/** The cockpit risk-envelope budget (remaining-R + the nested plan ⊆ book ⊆ owner envelopes) from
 * the plan-lifecycle {@link Budget}. `remainingR` is the fraction of the session's 1R still uncommitted
 * (`remaining / total`); the three envelopes are the session's 1R (rUsd IS 1R — a structural config
 * fact, not an invented value). Carries the optional {@link SizingHeadroom} (the max fillable size the
 * remaining-R budget admits) when the caller can source the exec price. Pure. */
export function budgetEnvelopeOf(budget: Budget | null | undefined, sizing?: SizingHeadroom | null): BudgetEnvelope {
  const total = budget?.total ?? null;
  const remaining = budget?.remaining ?? null;
  const remainingR =
    total !== null && total !== undefined && total > 0 && remaining !== null && remaining !== undefined
      ? remaining / total
      : 0;
  return {
    remainingR,
    planEnvelope: 1,
    bookEnvelope: 1,
    ownerEnvelope: 1,
    ...(sizing !== undefined && sizing !== null ? { sizing } : {}),
  };
}
