/**
 * Ion workflow engine CLI entry point.
 *
 * Pure Node.js CLI using process.argv parsing — no external argparse library.
 * Routes subcommands to their respective handler modules.
 *
 * @example
 *   node dist/cli/index.js workflow list --json
 *   node dist/cli/index.js workflow run deploy --cwd /tmp/project
 */

import { parseArgs, buildCliOptions, printJson, type CliOptions } from "./utils.js";

import { listCommand } from './commands/list.js';
import { runCommand } from './commands/run.js';
import { statusCommand } from './commands/status.js';
import { runsCommand } from './commands/runs.js';
import { approveCommand } from './commands/approve.js';
import { rejectCommand } from './commands/reject.js';
import { resumeCommand } from './commands/resume.js';
import { abandonCommand } from './commands/abandon.js';
import { cleanupCommand } from './commands/cleanup.js';
import { validateCommand } from './commands/validate.js';
import { convertCommand } from './commands/convert.js';

// ---------------------------------------------------------------------------
// Command registry
// ---------------------------------------------------------------------------

interface CommandEntry {
  name: string;
  description: string;
  usage: string;
  handler: (args: string[], options: CliOptions) => Promise<void>;
}

const COMMANDS: CommandEntry[] = [
  {
    name: 'list',
    description: 'List all available workflows',
    usage: 'workflow list [--json]',
    handler: listCommand,
  },
  {
    name: 'run',
    description: 'Execute a workflow by name',
    usage: 'workflow run <name> [args...] [--cwd <path>] [--detach] [--json]',
    handler: runCommand,
  },
  {
    name: 'status',
    description: 'Show active (running + paused) workflow runs',
    usage: 'workflow status [--json]',
    handler: statusCommand,
  },
  {
    name: 'runs',
    description: 'List recent workflow runs with filters',
    usage: 'workflow runs [--status <status>] [--limit N] [--all] [--json]',
    handler: runsCommand,
  },
  {
    name: 'approve',
    description: 'Approve a paused workflow run',
    usage: 'workflow approve <run-id> [comment] [--json]',
    handler: approveCommand,
  },
  {
    name: 'reject',
    description: 'Reject a paused workflow run',
    usage: 'workflow reject <run-id> [reason] [--json]',
    handler: rejectCommand,
  },
  {
    name: 'resume',
    description: 'Resume a failed workflow run',
    usage: 'workflow resume <run-id> [--json]',
    handler: resumeCommand,
  },
  {
    name: 'abandon',
    description: 'Cancel a non-terminal workflow run',
    usage: 'workflow abandon <run-id> [--json]',
    handler: abandonCommand,
  },
  {
    name: 'cleanup',
    description: 'Remove old workflow run artifacts',
    usage: 'workflow cleanup [days] [--json]',
    handler: cleanupCommand,
  },
  {
    name: 'validate',
    description: 'Validate a workflow definition without executing',
    usage: 'workflow validate <name> [--json]',
    handler: validateCommand,
  },
  {
    name: 'convert',
    description: 'Convert a .sop.md file to a YAML workflow definition',
    usage: 'workflow convert <file.sop.md> [--output <path>]',
    handler: convertCommand,
  },
];

// ---------------------------------------------------------------------------
// Help output
// ---------------------------------------------------------------------------

function printHelp(): void {
  console.log('');
  console.log('Ion — Workflow Engine CLI');
  console.log('');
  console.log('Usage:');
  console.log('  workflow <command> [options]');
  console.log('');
  console.log('Commands:');

  const maxNameLen = Math.max(...COMMANDS.map((c) => c.name.length));
  for (const cmd of COMMANDS) {
    const padded = cmd.name.padEnd(maxNameLen + 2);
    console.log(`  ${padded}${cmd.description}`);
  }

  console.log('');
  console.log('Global options:');
  console.log('  --json          Output as JSON (suppresses all other output)');
  console.log('  --cwd <path>    Set working directory');
  console.log('  --store <path>  Path to workflow store');
  console.log('  --db-path <p>   Path to database file');
  console.log('');
  console.log('Run "workflow <command> --help" for command-specific usage.');
  console.log('');
}

function printCommandHelp(cmd: CommandEntry): void {
  console.log('');
  console.log(`workflow ${cmd.name}`);
  console.log('');
  console.log(`  ${cmd.description}`);
  console.log('');
  console.log('Usage:');
  console.log(`  ${cmd.usage}`);
  console.log('');
}

// ---------------------------------------------------------------------------
// Main entry
// ---------------------------------------------------------------------------

export async function main(argv: string[] = process.argv.slice(2)): Promise<void> {
  const { args, options } = parseArgs(argv);
  const cliOptions = buildCliOptions(options);

  // --help with no command → general help
  if (args.length === 0 || options.help === true) {
    printHelp();
    process.exit(0);
  }

  const commandName = args[0];
  const commandArgs = args.slice(1);

  // --help after a command name → command-specific help
  if (options.help) {
    const cmd = COMMANDS.find((c) => c.name === commandName);
    if (cmd) {
      printCommandHelp(cmd);
    } else {
      console.error(`Unknown command: ${commandName}`);
      printHelp();
    }
    process.exit(0);
  }

  const command = COMMANDS.find((c) => c.name === commandName);

  if (!command) {
    console.error(`Unknown command: ${commandName}`);
    printHelp();
    process.exit(1);
    return; // unreachable, but satisfies TS control flow
  }

  try {
    await command.handler(commandArgs, cliOptions);
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : String(err);
    if (cliOptions.json) {
      printJson({ error: message });
    } else {
      console.error(`Error: ${message}`);
    }
    process.exit(1);
  }
}

// Run when executed directly (not imported).
// In ESM, check import.meta.url to detect direct execution.
const _directRun = typeof import.meta !== 'undefined' && import.meta.url;
if (_directRun) {
  main().catch((err: unknown) => {
    console.error(err);
    process.exit(1);
  });
}