/**
 * # cli/commands/_heavy — the lazy-load boundary (Kestrel CLI v1 §4)
 *
 * `loadHeavy` is the ONE gate every HEAVY handler passes through. It fails closed on a bun-less host
 * (exit 4, `RUNTIME_UNAVAILABLE`) — never a raw resolution stack, never a half-degraded verb. HEAVY
 * handlers call it at the point of use, so the bundled `dist/cli.js` only reaches for
 * `bun:sqlite`/`Bun.CryptoHasher`/chdb when a HEAVY command is actually invoked; LIGHT commands never
 * reach here and stay node-runnable with no bun/chdb.
 *
 * The guard is STRUCTURAL, not incidental (kestrel-mkn review B1). It used to rely purely on the
 * dynamic `import()` FAULTING on a `bun:*` specifier — which silently fails to fire for any heavy verb
 * whose module graph happens to load fine under node and only touches Bun through a LAZY global. That
 * was exactly the `agent` verb: its `{op:catalog}` ran to completion under bun-less node, and
 * `{op:openSession}` died with a raw `ReferenceError: Bun is not defined` on the protocol channel (exit
 * 1) instead of the loud exit-4 refusal every other heavy verb raises. So the runtime is now checked
 * BEFORE the import: no Bun ⇒ no heavy verb, whatever its import graph happens to look like.
 */

import { CliError, EXIT } from "../errors.ts";

function runtimeUnavailable(needsChdb: boolean): CliError {
  return new CliError({
    code: "RUNTIME_UNAVAILABLE",
    exit: EXIT.RUNTIME_UNAVAILABLE,
    message: "this command requires the Bun runtime" + (needsChdb ? " and the native chdb dependency" : ""),
    hint: "no usable Bun runtime found — reinstall with optional dependencies enabled (the package bundles `bun`), set KESTREL_BUN=/path/to/bun, or install Bun (https://bun.sh)",
  });
}

/**
 * Load a heavy module, or fail closed. Refuses UP FRONT under a bun-less runtime (the published bin
 * re-execs heavy verbs onto a bun, so reaching this on node means no bun exists anywhere), and maps any
 * remaining load failure — a missing native chdb, say — onto the same loud exit-4 error.
 */
export async function loadHeavy<T>(imp: () => Promise<T>): Promise<T> {
  // Fail closed BEFORE the import: a heavy verb must never half-run under node and surface its
  // Bun-shaped fault as some unrelated domain error (a bogus `corrupt-content-root`, a raw TypeError).
  if (process.versions.bun === undefined) throw runtimeUnavailable(false);
  try {
    return await imp();
  } catch (e) {
    const s = String(e instanceof Error ? e.message : e);
    throw runtimeUnavailable(/chdb/i.test(s));
  }
}
