/**
 * Gateway bootstrap stage — creates the first admin user and persists the
 * admin API token.
 *
 * Runs as the terminal stage of the unified first-run wizard and is also
 * invoked by the `mosaic gateway install` standalone entry point after the
 * config stage. Idempotent: if an admin already exists, this stage offers
 * inline token recovery instead of re-prompting for credentials.
 */

import { join } from 'node:path';
import type { WizardPrompter } from '../prompter/interface.js';
import type { WizardState } from '../types.js';
import { promptMaskedConfirmed } from '../prompter/masked-prompt.js';

// ── Headless detection ────────────────────────────────────────────────────────

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

// ── Options ───────────────────────────────────────────────────────────────────

export interface GatewayBootstrapStageOptions {
  host: string;
  port: number;
}

export interface GatewayBootstrapStageResult {
  completed: boolean;
}

// ── Stage ─────────────────────────────────────────────────────────────────────

export async function gatewayBootstrapStage(
  p: WizardPrompter,
  state: WizardState,
  opts: GatewayBootstrapStageOptions,
): Promise<GatewayBootstrapStageResult> {
  const { host, port } = opts;
  const baseUrl = `http://${host}:${port.toString()}`;

  const { readMeta, writeMeta, GATEWAY_HOME } = await import('../commands/gateway/daemon.js');
  const existingMeta = readMeta();
  if (!existingMeta) {
    p.warn('Gateway meta.json missing — cannot bootstrap admin user.');
    return { completed: false };
  }

  // Check whether an admin already exists.
  let needsSetup: boolean;
  try {
    const statusRes = await fetch(`${baseUrl}/api/bootstrap/status`);
    if (!statusRes.ok) {
      p.warn('Could not check bootstrap status — skipping first user setup.');
      return { completed: false };
    }
    const status = (await statusRes.json()) as { needsSetup: boolean };
    needsSetup = status.needsSetup;
  } catch {
    p.warn('Could not reach gateway bootstrap endpoint — skipping first user setup.');
    return { completed: false };
  }

  if (!needsSetup) {
    if (existingMeta.adminToken) {
      p.log('Admin user already exists (token on file).');
      return { completed: true };
    }

    // Admin exists but no token on file — offer inline recovery if interactive.
    p.warn('Admin user already exists but no admin token is on file.');

    // Headless re-install: treat this as a successful no-op. The gateway has
    // already been bootstrapped; a scripted re-run should not fail simply
    // because the local admin-token cache has been cleared. Operators can
    // run `mosaic gateway config recover-token` interactively later.
    if (isHeadless()) {
      p.log(
        'Headless mode — leaving existing admin in place. Run `mosaic gateway config recover-token` to restore local token access.',
      );
      return { completed: true };
    }

    const runRecovery = await p.confirm({
      message: 'Run token recovery now?',
      initialValue: true,
    });
    if (runRecovery) {
      try {
        const { ensureSession, mintAdminToken, persistToken } =
          await import('../commands/gateway/token-ops.js');
        const cookie = await ensureSession(baseUrl);
        const label = `CLI recovery token (${new Date()
          .toISOString()
          .slice(0, 16)
          .replace('T', ' ')})`;
        const minted = await mintAdminToken(baseUrl, cookie, label);
        persistToken(baseUrl, minted);
        return { completed: true };
      } catch (err) {
        p.warn(`Token recovery failed: ${err instanceof Error ? err.message : String(err)}`);
        return { completed: false };
      }
    }

    p.log('No admin token on file. Run: mosaic gateway config recover-token');
    return { completed: false };
  }

  // Fresh bootstrap — collect admin credentials.
  p.note('Admin User Setup', 'Create your first admin user');

  let name: string;
  let email: string;
  let password: string;

  if (isHeadless()) {
    const nameEnv = process.env['MOSAIC_ADMIN_NAME']?.trim() ?? '';
    const emailEnv = process.env['MOSAIC_ADMIN_EMAIL']?.trim() ?? '';
    const passwordEnv = process.env['MOSAIC_ADMIN_PASSWORD'] ?? '';

    const missing: string[] = [];
    if (!nameEnv) missing.push('MOSAIC_ADMIN_NAME');
    if (!emailEnv) missing.push('MOSAIC_ADMIN_EMAIL');
    if (!passwordEnv) missing.push('MOSAIC_ADMIN_PASSWORD');

    if (missing.length > 0) {
      p.warn('Headless admin bootstrap requires env vars: ' + missing.join(', '));
      return { completed: false };
    }
    if (passwordEnv.length < 8) {
      p.warn('MOSAIC_ADMIN_PASSWORD must be at least 8 characters.');
      return { completed: false };
    }

    name = nameEnv;
    email = emailEnv;
    password = passwordEnv;
  } else {
    name = await p.text({
      message: 'Admin name',
      validate: (v) => (v.trim().length === 0 ? 'Name is required' : undefined),
    });
    email = await p.text({
      message: 'Admin email',
      validate: (v) => (v.trim().length === 0 ? 'Email is required' : undefined),
    });
    password = await promptMaskedConfirmed(
      'Admin password (min 8 chars): ',
      'Confirm password:            ',
      (v) => (v.length < 8 ? 'Password must be at least 8 characters' : undefined),
    );
  }

  state.gateway = {
    ...(state.gateway ?? {
      host,
      port,
      tier: 'local',
      corsOrigin: `http://${host}:3000`,
    }),
    admin: { name, email, password },
  };

  // Call bootstrap setup.
  try {
    const res = await fetch(`${baseUrl}/api/bootstrap/setup`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name, email, password }),
    });

    if (!res.ok) {
      const body = await res.text().catch(() => '');
      p.warn(`Bootstrap failed (${res.status.toString()}): ${body}`);
      return { completed: false };
    }

    const result = (await res.json()) as {
      user: { id: string; email: string };
      token: { plaintext: string };
    };

    // Persist the token so future CLI calls can authenticate automatically.
    const meta = { ...existingMeta, adminToken: result.token.plaintext };
    writeMeta(meta);

    if (state.gateway) {
      state.gateway.adminTokenIssued = true;
    }

    p.log(`Admin user created: ${result.user.email}`);
    printAdminTokenBanner(p, result.token.plaintext, join(GATEWAY_HOME, 'meta.json'));
    return { completed: true };
  } catch (err) {
    p.warn(`Bootstrap error: ${err instanceof Error ? err.message : String(err)}`);
    return { completed: false };
  }
}

// ── Banner ────────────────────────────────────────────────────────────────────

function printAdminTokenBanner(p: WizardPrompter, token: string, metaPath: string): void {
  const body = [
    '  Save this token now — it will not be shown again in full.',
    `    ${token}`,
    '',
    `  Stored (read-only) at: ${metaPath}`,
    '',
    '  Use it with admin endpoints, e.g.:',
    '    mosaic gateway --token <token> status',
  ].join('\n');
  p.note(body, 'Admin API Token');
}
