#!/usr/bin/env node
import { existsSync, readFileSync } from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';

const binDir = path.dirname(fileURLToPath(import.meta.url));
const appDir = path.resolve(binDir, '..');
const userStateDir = path.join(os.homedir(), '.nterminal');

const [command = 'help', ...args] = process.argv.slice(2);

function defaultEnv() {
  const env = {
    ...process.env,
    NTERMINAL_APP_DIR: process.env.NTERMINAL_APP_DIR ?? appDir
  };
  env.NTERMINAL_ENV_FILE ??= path.join(userStateDir, '.env');
  env.NTERMINAL_RUNTIME_STATE_PATH ??= path.join(userStateDir, 'state.json');
  env.NTERMINAL_RUNTIME_PID_PATH ??= path.join(userStateDir, 'nterminal.pid');
  env.NTERMINAL_RUNTIME_MONITOR_PID_PATH ??= path.join(userStateDir, 'nterminal.monitor.pid');
  env.NTERMINAL_RUNTIME_LOG_PATH ??= path.join(userStateDir, 'nterminal.log');
  return env;
}

function run(executable, runArgs) {
  const result = spawnSync(executable, runArgs, {
    cwd: appDir,
    stdio: 'inherit',
    env: defaultEnv()
  });
  process.exit(result.status ?? 1);
}

function runNode(modulePath, runArgs) {
  run(process.execPath, [modulePath, ...runArgs]);
}

function scriptEntrypoint(name) {
  const built = path.join(appDir, 'dist', 'scripts', `${name}.js`);
  if (existsSync(built)) {
    return built;
  }
  return null;
}

function runScript(name, runArgs) {
  const entrypoint = scriptEntrypoint(name);
  if (!entrypoint) {
    console.error(`error: ${name} entrypoint not found; reinstall nterminal`);
    process.exit(1);
  }
  runNode(entrypoint, runArgs);
}

function runCtl(runArgs) {
  run('bash', [path.join(appDir, 'scripts', 'nterminalctl'), ...runArgs]);
}

function packageVersion() {
  try {
    const packageJson = JSON.parse(readFileSync(path.join(appDir, 'package.json'), 'utf8'));
    if (typeof packageJson.version === 'string' && packageJson.version) {
      return packageJson.version;
    }
  } catch {
    // Fall through to a stable string so version checks never invoke nterminalctl.
  }
  return 'unknown';
}

function printVersion() {
  console.log(packageVersion());
}

function printHelp() {
  console.log(`Usage: nterminal <command>

Commands:
  version                 Print the installed NTerminal version.
  onboarding              Run interactive main/secondary onboarding.
  generate-secrets        Print a new NTERMINAL_SESSION_SECRET.
  status                  Show process status.
  start                   Start the built server.
  stop                    Stop the managed server.
  restart                 Restart the managed server.
  restart-after-update    Restart after replacing the npm package.
  build                   Verify the bundled runtime exists.
  deploy                  Restart the installed package.
  clean --force           Remove local runtime state.
  uninstall --force       Stop and remove local runtime state before npm uninstall.
  logs [N]                Show recent logs.
  logs -f [N]             Follow logs.
  doctor                  Check local runtime readiness.
  pid                     Print the running PID.
  url                     Print the configured local URL.
  help                    Show this help.
`);
}

switch (command) {
  case 'onboarding':
    runScript('onboarding', args);
    break;
  case 'generate-secrets':
  case 'generate:secrets':
    runScript('generate-secrets', args);
    break;
  case 'ctl':
    runCtl(args);
    break;
  case 'version':
  case '-v':
  case '--version':
    printVersion();
    break;
  case 'help':
  case '-h':
  case '--help':
    printHelp();
    break;
  default:
    runCtl([command, ...args]);
}
