import type { Command } from 'commander';
import {
  getDaemonPid,
  readMeta,
  startDaemon,
  stopDaemon,
  waitForHealth,
} from './gateway/daemon.js';
import { getGatewayUrl } from './gateway/login.js';

interface GatewayParentOpts {
  host: string;
  port: string;
  token?: string;
}

function resolveOpts(raw: GatewayParentOpts): { host: string; port: number; token?: string } {
  const meta = readMeta();
  return {
    host: raw.host ?? meta?.host ?? 'localhost',
    port: parseInt(raw.port, 10) || meta?.port || 14242,
    token: raw.token ?? meta?.adminToken,
  };
}

export function registerGatewayCommand(program: Command): void {
  const gw = program
    .command('gateway')
    .description('Manage the Mosaic gateway daemon')
    .helpOption('--help', 'Display help')
    .option('-h, --host <host>', 'Gateway host', 'localhost')
    .option('-p, --port <port>', 'Gateway port', '14242')
    .option('-t, --token <token>', 'Admin API token')
    .configureHelp({ sortSubcommands: true })
    .action(() => {
      gw.outputHelp();
    });

  // ─── install ────────────────────────────────────────────────────────────

  gw.command('install')
    .description('Install and configure the gateway daemon')
    .option('--skip-install', 'Skip npm package installation (use local build)')
    .action(async (cmdOpts: { skipInstall?: boolean }) => {
      const opts = resolveOpts(gw.opts() as GatewayParentOpts);
      const { runInstall } = await import('./gateway/install.js');
      await runInstall({ ...opts, skipInstall: cmdOpts.skipInstall });
    });

  // ─── start ──────────────────────────────────────────────────────────────

  gw.command('start')
    .description('Start the gateway daemon')
    .action(async () => {
      const opts = resolveOpts(gw.opts() as GatewayParentOpts);
      try {
        const pid = startDaemon();
        console.log(`Gateway started (PID ${pid.toString()})`);
        console.log('Waiting for health...');
        const healthy = await waitForHealth(opts.host, opts.port);
        if (healthy) {
          console.log(`Gateway ready at http://${opts.host}:${opts.port.toString()}`);
        } else {
          console.warn('Gateway started but health check timed out. Check logs.');
        }
      } catch (err) {
        console.error(err instanceof Error ? err.message : String(err));
        process.exit(1);
      }
    });

  // ─── stop ───────────────────────────────────────────────────────────────

  gw.command('stop')
    .description('Stop the gateway daemon')
    .action(async () => {
      try {
        await stopDaemon();
        console.log('Gateway stopped.');
      } catch (err) {
        console.error(err instanceof Error ? err.message : String(err));
        process.exit(1);
      }
    });

  // ─── restart ────────────────────────────────────────────────────────────

  gw.command('restart')
    .description('Restart the gateway daemon')
    .action(async () => {
      const opts = resolveOpts(gw.opts() as GatewayParentOpts);
      const pid = getDaemonPid();
      if (pid !== null) {
        console.log('Stopping gateway...');
        await stopDaemon();
      }
      console.log('Starting gateway...');
      try {
        const newPid = startDaemon();
        console.log(`Gateway started (PID ${newPid.toString()})`);
        const healthy = await waitForHealth(opts.host, opts.port);
        if (healthy) {
          console.log(`Gateway ready at http://${opts.host}:${opts.port.toString()}`);
        } else {
          console.warn('Gateway started but health check timed out. Check logs.');
        }
      } catch (err) {
        console.error(err instanceof Error ? err.message : String(err));
        process.exit(1);
      }
    });

  // ─── status ─────────────────────────────────────────────────────────────

  gw.command('status')
    .description('Show gateway daemon status and health')
    .action(async () => {
      const opts = resolveOpts(gw.opts() as GatewayParentOpts);
      const { runStatus } = await import('./gateway/status.js');
      await runStatus(opts);
    });

  // ─── login ──────────────────────────────────────────────────────────────

  gw.command('login')
    .description('Sign in to the gateway (defaults to URL from meta.json)')
    .option('-g, --gateway <url>', 'Gateway URL (overrides meta.json)')
    .option('-e, --email <email>', 'Email address')
    .option(
      '-p, --password <password>',
      '[UNSAFE] Avoid — exposes credentials in shell history and process listings',
    )
    .action(async (cmdOpts: { gateway?: string; email?: string; password?: string }) => {
      const { runLogin } = await import('./gateway/login.js');
      const url = getGatewayUrl(cmdOpts.gateway);
      if (cmdOpts.password) {
        console.warn(
          'Warning: --password flag exposes credentials in shell history and process listings.',
        );
      }
      try {
        await runLogin({ gatewayUrl: url, email: cmdOpts.email, password: cmdOpts.password });
      } catch (err) {
        console.error(err instanceof Error ? err.message : String(err));
        process.exit(1);
      }
    });

  // ─── config ─────────────────────────────────────────────────────────────

  const configCmd = gw
    .command('config')
    .description('View or modify gateway configuration')
    .option('--set <KEY=VALUE>', 'Set a configuration value')
    .option('--unset <KEY>', 'Remove a configuration key')
    .option('--edit', 'Open config in $EDITOR')
    .action(async (cmdOpts: { set?: string; unset?: string; edit?: boolean }) => {
      const { runConfig } = await import('./gateway/config.js');
      await runConfig(cmdOpts);
    });

  configCmd
    .command('rotate-token')
    .description('Mint a new admin token using the stored BetterAuth session')
    .option('-g, --gateway <url>', 'Gateway URL (overrides meta.json)')
    .action(async (cmdOpts: { gateway?: string }) => {
      const { runRotateToken } = await import('./gateway/token-ops.js');
      await runRotateToken(cmdOpts.gateway);
    });

  configCmd
    .command('recover-token')
    .description('Recover an admin token — prompts for login if no valid session exists')
    .option('-g, --gateway <url>', 'Gateway URL (overrides meta.json)')
    .action(async (cmdOpts: { gateway?: string }) => {
      const { runRecoverToken } = await import('./gateway/token-ops.js');
      await runRecoverToken(cmdOpts.gateway);
    });

  // ─── logs ───────────────────────────────────────────────────────────────

  gw.command('logs')
    .description('View gateway daemon logs')
    .option('-f, --follow', 'Follow log output')
    .option('-n, --lines <count>', 'Number of lines to show', '50')
    .action(async (cmdOpts: { follow?: boolean; lines?: string }) => {
      const { runLogs } = await import('./gateway/logs.js');
      runLogs({ follow: cmdOpts.follow, lines: parseInt(cmdOpts.lines ?? '50', 10) });
    });

  // ─── verify ─────────────────────────────────────────────────────────────

  gw.command('verify')
    .description('Verify the gateway installation (health, token, bootstrap endpoint)')
    .action(async () => {
      const opts = resolveOpts(gw.opts() as GatewayParentOpts);
      const { runVerify } = await import('./gateway/verify.js');
      await runVerify(opts);
    });

  // ─── uninstall ──────────────────────────────────────────────────────────

  gw.command('uninstall')
    .description('Uninstall the gateway daemon and optionally remove data')
    .action(async () => {
      const { runUninstall } = await import('./gateway/uninstall.js');
      await runUninstall();
    });

  // ─── doctor ─────────────────────────────────────────────────────────────────

  gw.command('doctor')
    .description('Check gateway tier and per-service health (PG, Valkey, pgvector)')
    .option('--json', 'Emit TierHealthReport as JSON to stdout (suppresses all other output)')
    .option('--config <path>', 'Path to mosaic.config.json (defaults to cwd or ~/.mosaic/)')
    .action(async (cmdOpts: { json?: boolean; config?: string }) => {
      const { runGatewayDoctor } = await import('./gateway-doctor.js');
      await runGatewayDoctor({ json: cmdOpts.json, config: cmdOpts.config });
    });
}
