/**
 * `madarx` subcommand router.
 *
 * Bare `madarx` (no subcommand) runs the full stack — web + cron + heartbeat
 * + WhatsApp — modeled on bare `hermes`. Subcommands mirror the Hermes surface.
 *
 * T1 wires: run (default), version, help. The interactive/operational commands
 * (setup, doctor, status — T2; update — T3) and supervisory commands (stop,
 * whatsapp, uninstall) are recognized here and print a clear "not yet wired"
 * notice naming the owning task, so the CLI surface is complete and testable now.
 */

import path from 'node:path';
import fs from 'node:fs';
import { fileURLToPath } from 'node:url';

const here = path.dirname(fileURLToPath(import.meta.url));
export const PKG_ROOT = path.resolve(here, '..', '..');

/** Recognized-but-deferred commands → owning task, shown in help + on invocation. */
const DEFERRED_COMMANDS = {
  stop: 'a later task (process supervisor)',
  whatsapp: 'T2 follow-up (pairing/reset)',
};

const ALIASES = {
  start: 'run',
  '--version': 'version',
  '-v': 'version',
  '--help': 'help',
  '-h': 'help',
  help: 'help',
};

/**
 * Parse argv (already sliced past `node bin/madarx.mjs`) into a command +
 * positional args + flags. Pure and side-effect-free for unit testing.
 *
 * @param {string[]} argv
 * @returns {{ command: string, args: string[], flags: Record<string, string|boolean> }}
 */
export function parseArgs(argv = []) {
  const flags = {};
  const positionals = [];
  for (const tok of argv) {
    if (tok.startsWith('--')) {
      const [k, v] = tok.slice(2).split('=');
      flags[k] = v === undefined ? true : v;
    } else if (tok.startsWith('-') && tok.length > 1 && !/^-\d/.test(tok)) {
      flags[tok.slice(1)] = true;
    } else {
      positionals.push(tok);
    }
  }

  // First positional is the command. A leading flag with no positional (e.g.
  // `--version`) maps through ALIASES. Otherwise default to `run`.
  let raw = positionals.shift();
  if (!raw) {
    if (flags.version || flags.v) raw = 'version';
    else if (flags.help || flags.h) raw = 'help';
    else raw = 'run';
  }
  const command = ALIASES[raw] || raw;
  return { command, args: positionals, flags };
}

export function readVersion() {
  try {
    const pkg = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, 'package.json'), 'utf8'));
    return pkg.version || '0.0.0';
  } catch {
    return '0.0.0';
  }
}

export function helpText() {
  return [
    'madarX OS — local-first agent orchestrator',
    '',
    'Usage: madarx [command] [options]',
    '',
    'Commands:',
    '  run            Boot web + cron + heartbeat + WhatsApp, open the dashboard (default)',
    '  setup          Interactive setup: data home, master key, folder grants, keys',
    '  status         Show component status (version, web, approvals, whatsapp)',
    '  doctor         Diagnose Node version, data home, master key, port',
    '  update         Update to the latest release (npm i -g madarx@latest)',
    '  whatsapp       Pair / reset the WhatsApp bridge                                [' + DEFERRED_COMMANDS.whatsapp + ']',
    '  stop           Stop a running instance                                         [' + DEFERRED_COMMANDS.stop + ']',
    '  uninstall      Remove the global install (--purge also deletes ~/.madarx)',
    '  version        Print the version',
    '  help           Show this help',
    '',
    'Data home: $MADARX_HOME (default ~/.madarx). Web tier on http://127.0.0.1:8787/',
    'Disable WhatsApp on run: MADARX_DISABLE_WHATSAPP=1',
  ].join('\n');
}

/**
 * Execute a parsed command. Returns a numeric exit code (0 = ok). `run` only
 * returns if it fails to boot — on success it blocks until the stack is stopped.
 *
 * @param {string[]} argv argv sliced past the node + script path
 */
export async function dispatch(argv = []) {
  const { command, args, flags } = parseArgs(argv);

  if (command === 'help') {
    console.log(helpText());
    return 0;
  }
  if (command === 'version') {
    console.log(readVersion());
    return 0;
  }
  if (command === 'run') {
    const { run } = await import('./run.js');
    return await run({ args, flags });
  }
  if (command === 'setup') {
    const { setup } = await import('./setup.js');
    return await setup({ args, flags });
  }
  if (command === 'doctor') {
    const { doctor } = await import('./doctor.js');
    return await doctor();
  }
  if (command === 'status') {
    const { status } = await import('./status.js');
    return await status();
  }
  if (command === 'update') {
    const { update } = await import('./update.js');
    return await update({ args, flags });
  }
  if (command === 'uninstall') {
    const { uninstall } = await import('./uninstall.js');
    return await uninstall({ args, flags });
  }
  if (command in DEFERRED_COMMANDS) {
    console.error(`\`madarx ${command}\` is not wired yet — landing in ${DEFERRED_COMMANDS[command]}.`);
    console.error('Run `madarx help` for what works today.');
    return 2;
  }

  console.error(`Unknown command: ${command}\n`);
  console.error(helpText());
  return 1;
}
