/**
 * # session/specs — the driver's PURE session-header helpers (META → instruments), factored light
 *
 * `requireMeta` / `resolveSpecs` / `specFromMeta` are the sim driver's own header rules: find the
 * one META a well-formed bus opens with, and resolve the session's {@link InstrumentSpec}s from it.
 * They were born inside `src/session/sim.ts` and are re-exported from there unchanged; this module
 * exists so a consumer that must stay OFF the heavy session graph — the CLI's `validate --arm`
 * context derivation (kestrel-elu9), which is LIGHT/node-runnable — can reuse the EXACT derivation
 * a real run performs instead of re-implementing a copy that could drift (AGENTS.md: validation
 * must match execution). Type-only imports; zero runtime dependencies; no `bun:*`, no IO, no clock.
 */

import type { BusEvent, MetaEvent, SessionInstrument } from "../bus/types.ts";
import type { InstrumentSpec } from "../engine/plans.ts";

/** A default {@link InstrumentSpec} from a bus META instrument. Contract facts are not on the v1
 * META, so they are DERIVED from the asset class: an `option-underlier` (SPX, SPY, …) gets the
 * standard listed-option shape — tick `0.01`, strike step `1`, **multiplier `100`** (premiums and
 * P&L are per-contract-×-100 dollars) — while a non-option underlier keeps multiplier `1`. An
 * explicit `instruments` override on `RunSimOptions` still wins. */
export function specFromMeta(si: SessionInstrument): InstrumentSpec {
  const isOption = si.assetClass === "option-underlier";
  return {
    symbol: si.symbol,
    tickSize: 0.01,
    strikeStep: 1,
    multiplier: isOption ? 100 : 1,
    ...(si.role !== undefined ? { role: si.role } : {}),
  };
}

/** Resolve the session's instrument specs from options + META, failing closed on none. */
export function resolveSpecs(meta: MetaEvent, override?: readonly InstrumentSpec[]): InstrumentSpec[] {
  const specs = override !== undefined ? [...override] : meta.instruments.map(specFromMeta);
  if (specs.length === 0) throw new Error("session: no instruments (fail-closed, RUNTIME §8)");
  return specs;
}

/** Find the single META header, failing closed on its absence (RUNTIME §8). */
export function requireMeta(events: readonly BusEvent[]): MetaEvent {
  const meta = events.find((e): e is MetaEvent => e.stream === "META");
  if (meta === undefined) {
    throw new Error("session: no META header in bus (a well-formed bus opens with exactly one META, RUNTIME §8)");
  }
  return meta;
}
