/**
 * Thin wrapper over the unified first-run stages.
 *
 * `mosaic gateway install` is kept as a standalone entry point for users who
 * already went through `mosaic wizard` and only need to (re)configure the
 * gateway daemon. It builds a minimal `WizardState`, invokes
 * `gatewayConfigStage` and `gatewayBootstrapStage` directly, and returns.
 *
 * The heavy lifting — prompts, env writes, daemon lifecycle, bootstrap POST —
 * lives in `packages/mosaic/src/stages/gateway-config.ts` and
 * `packages/mosaic/src/stages/gateway-bootstrap.ts` so that the same code
 * path runs under both the unified wizard and this standalone command.
 */

import { homedir } from 'node:os';
import { join } from 'node:path';
import { ClackPrompter } from '../../prompter/clack-prompter.js';
import type { WizardState } from '../../types.js';

interface InstallOpts {
  host: string;
  port: number;
  skipInstall?: boolean;
}

function isHeadlessRun(): boolean {
  return process.env['MOSAIC_ASSUME_YES'] === '1' || !process.stdin.isTTY;
}

export async function runInstall(opts: InstallOpts): Promise<void> {
  const mosaicHome = process.env['MOSAIC_HOME'] ?? join(homedir(), '.config', 'mosaic');

  const prompter = new ClackPrompter();

  const state: WizardState = {
    mosaicHome,
    sourceDir: mosaicHome,
    mode: 'quick',
    installAction: 'fresh',
    soul: {},
    user: {},
    tools: {},
    runtimes: { detected: [], mcpConfigured: false },
    selectedSkills: [],
  };

  const { gatewayConfigStage } = await import('../../stages/gateway-config.js');
  const { gatewayBootstrapStage } = await import('../../stages/gateway-bootstrap.js');

  // Preserve the legacy "explicit --port wins over saved config" semantic:
  // commander defaults the port to 14242, so any other value is treated as
  // an explicit user override that the config stage should honor even on
  // resume.
  const portOverride = opts.port !== 14242 ? opts.port : undefined;

  const headless = isHeadlessRun();

  try {
    const configResult = await gatewayConfigStage(prompter, state, {
      host: opts.host,
      defaultPort: opts.port,
      portOverride,
      skipInstall: opts.skipInstall,
    });

    if (!configResult.ready || !configResult.host || configResult.port === undefined) {
      // In headless/scripted installs, a non-ready config stage is a fatal
      // error — we must not report "complete" when the gateway was never
      // configured. Exit non-zero so CI notices.
      if (headless) {
        prompter.warn('Gateway configuration failed in headless mode — aborting.');
        process.exit(1);
      }
      return;
    }

    const bootstrapResult = await gatewayBootstrapStage(prompter, state, {
      host: configResult.host,
      port: configResult.port,
    });

    if (!bootstrapResult.completed && headless) {
      prompter.warn('Admin bootstrap failed in headless mode — aborting.');
      process.exit(1);
    }

    prompter.log('─── Installation Complete ───');
    prompter.log(`  Endpoint:  http://${configResult.host}:${configResult.port.toString()}`);
    prompter.log(`  Logs:      mosaic gateway logs`);
    prompter.log(`  Status:    mosaic gateway status`);

    // Post-install verification (CU-07-03) — non-fatal.
    try {
      const { runPostInstallVerification } = await import('./verify.js');
      await runPostInstallVerification(configResult.host, configResult.port);
    } catch {
      // Non-fatal — verification is a courtesy
    }
  } catch (err) {
    // Stages normally return structured results for expected failures.
    // Anything that reaches here is an unexpected runtime error — render a
    // concise warning AND re-throw so the command exits non-zero. Silent
    // swallowing would let scripted installs report success on failure.
    prompter.warn(`Gateway install failed: ${err instanceof Error ? err.message : String(err)}`);
    throw err;
  }
}
