#!/usr/bin/env bun
/**
 * Legacy-compatible CLI shim (§13 Q6, AGENTS.md §8 Phase 11).
 *
 * Accepts the old EtherCalc flag surface (--key, --cors, --port, --host,
 * --expire, --basepath, --keyfile, --certfile) and translates them into
 * wrangler dev invocation + Miniflare env vars. All translation logic
 * lives in `packages/cli/` where it is 100% unit-tested; this shim is
 * the thin IO wrapper that connects it to real stdio and `spawnSync`.
 *
 * Why bun shebang: the workspace is bun-first (commit 042b731). Bun also
 * runs Node's CommonJS + ESM, so `bunx wrangler` works out of the box.
 * Fallback for pure-Node environments: `node bin/ethercalc` also works
 * because bun-specific syntax is avoided below.
 */
import { spawnSync } from 'node:child_process';
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { main } from '../packages/cli/src/run.ts';
import { main as migrateMain } from '../packages/migrate/src/cli.ts';
import { RespClient } from '../packages/migrate/src/resp-client.ts';

const here = path.dirname(fileURLToPath(import.meta.url));
const workerCwd = path.resolve(here, '..', 'packages', 'worker');

const argv = process.argv.slice(2);

// Subcommand dispatch. `ethercalc migrate <flags…>` forwards to the
// RESP-source migrator in `packages/migrate`. All other argv forms fall
// through to the wrangler-dev launcher (legacy flag surface).
if (argv[0] === 'migrate') {
  const code = await migrateMain(argv.slice(1), {
    connectRedis: (url) => RespClient.connect(url),
    // `node:fs/promises` satisfies the narrow FsLike shape — used when
    // `--source file://…` or `--source /abs/path` selects the on-disk
    // dump source (e.g. Sandstorm grains, Docker self-host).
    fs,
    stdout: (s) => process.stdout.write(s),
    stderr: (s) => process.stderr.write(s),
  });
  process.exit(code);
}

// Forward selected ETHERCALC_* env vars from the parent shell into
// wrangler as `--var KEY:VALUE` flags. Wrangler only exposes env vars
// to the worker as bindings when they come via `[vars]`, `.dev.vars`,
// `wrangler secret put`, or `--var`. Sandstorm grains (and anyone
// self-hosting in a read-only-/opt-style container) can't write
// `.dev.vars` into the packaged worker dir, so this CLI flag path is
// the Unix-y escape hatch. Only the narrow set that the Worker reads
// gets whitelisted — we don't launder arbitrary env vars into Worker
// bindings (CF would reject unknown ones anyway, but being explicit
// is cheap).
const WRANGLER_VAR_PASSTHROUGH: readonly string[] = [
  'BASEPATH',
  'DEVMODE',
  'ETHERCALC_CORS',
  'ETHERCALC_DEFAULT_ROOM',
  'ETHERCALC_DISABLE_ROOM_INDEX',
  'ETHERCALC_EXPIRE',
  'ETHERCALC_KEY',
  'ETHERCALC_RATELIMIT',
  'ETHERCALC_ROOM_CREATE_LIMIT',
  'ETHERCALC_SANDSTORM',
  'ETHERCALC_MIGRATE_TOKEN',
];

const code = main(argv, {
  stdout: (s) => process.stdout.write(s),
  stderr: (s) => process.stderr.write(s),
  env: process.env,
  exec: (cmd, args, extraEnv) => {
    const extraArgs: string[] = [];
    const mergedEnv = { ...process.env, ...extraEnv };
    for (const key of WRANGLER_VAR_PASSTHROUGH) {
      const value = mergedEnv[key];
      if (value !== undefined && value !== '') {
        extraArgs.push('--var', `${key}:${value}`);
      }
    }
    const result = spawnSync(cmd, [...args, ...extraArgs], {
      cwd: workerCwd,
      env: mergedEnv,
      stdio: 'inherit',
    });
    if (result.error) {
      process.stderr.write(`ethercalc: failed to launch ${cmd}: ${result.error.message}\n`);
      return 127;
    }
    return result.status ?? 0;
  },
});
process.exit(code);
