import { readMeta } from './daemon.js';

// ANSI colour helpers (gracefully degrade when not a TTY)
const isTTY = Boolean(process.stdout.isTTY);
const G = isTTY ? '\x1b[0;32m' : '';
const R = isTTY ? '\x1b[0;31m' : '';
const BOLD = isTTY ? '\x1b[1m' : '';
const RESET = isTTY ? '\x1b[0m' : '';

function ok(label: string): void {
  process.stdout.write(`  ${G}✔${RESET}  ${label.padEnd(36)}${G}[ok]${RESET}\n`);
}

function fail(label: string, hint: string): void {
  process.stdout.write(`  ${R}✖${RESET}  ${label.padEnd(36)}${R}[FAIL]${RESET}\n`);
  process.stdout.write(`     ${R}↳ ${hint}${RESET}\n`);
}

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function fetchWithRetry(
  url: string,
  opts: RequestInit = {},
  retries = 3,
  delayMs = 1000,
): Promise<Response | null> {
  for (let attempt = 0; attempt < retries; attempt++) {
    try {
      const res = await fetch(url, opts);
      // Retry on non-OK responses too — the gateway may still be starting up
      // (e.g. 503 before the app bootstrap completes).
      if (res.ok) return res;
    } catch {
      // Network-level error — not ready yet, will retry
    }
    if (attempt < retries - 1) await sleep(delayMs);
  }
  return null;
}

export interface VerifyResult {
  gatewayHealthy: boolean;
  adminTokenOnFile: boolean;
  bootstrapReachable: boolean;
  allPassed: boolean;
}

/**
 * Run post-install verification checks.
 *
 * @param host - Gateway hostname (e.g. "localhost")
 * @param port - Gateway port (e.g. 14242)
 * @returns VerifyResult — callers can inspect individual flags
 */
export async function runPostInstallVerification(
  host: string,
  port: number,
): Promise<VerifyResult> {
  const baseUrl = `http://${host}:${port.toString()}`;

  console.log(`\n${BOLD}Mosaic installation verified:${RESET}`);

  // ─── Check 1: Gateway /health ─────────────────────────────────────────────
  const healthRes = await fetchWithRetry(`${baseUrl}/health`);
  const gatewayHealthy = healthRes !== null && healthRes.ok;
  if (gatewayHealthy) {
    ok('gateway healthy');
  } else {
    fail('gateway healthy', 'Run: mosaic gateway status  /  mosaic gateway logs');
  }

  // ─── Check 2: Admin token on file ─────────────────────────────────────────
  const meta = readMeta();
  const adminTokenOnFile = Boolean(meta?.adminToken && meta.adminToken.length > 0);
  if (adminTokenOnFile) {
    ok('admin token on file');
  } else {
    fail('admin token on file', 'Run: mosaic gateway config recover-token');
  }

  // ─── Check 3: Bootstrap endpoint reachable ────────────────────────────────
  const bootstrapRes = await fetchWithRetry(`${baseUrl}/api/bootstrap/status`);
  const bootstrapReachable = bootstrapRes !== null && bootstrapRes.ok;
  if (bootstrapReachable) {
    ok('bootstrap endpoint reach');
  } else {
    fail('bootstrap endpoint reach', 'Run: mosaic gateway status  /  mosaic gateway logs');
  }

  const allPassed = gatewayHealthy && adminTokenOnFile && bootstrapReachable;

  if (!allPassed) {
    console.log(
      `\n${R}One or more checks failed.${RESET} Recovery commands listed above.\n` +
        `Use ${BOLD}mosaic gateway status${RESET} and ${BOLD}mosaic gateway config recover-token${RESET} to investigate.\n`,
    );
  }

  return { gatewayHealthy, adminTokenOnFile, bootstrapReachable, allPassed };
}

/**
 * Standalone entry point for `mosaic gateway verify`.
 * Reads host/port from meta.json if not provided.
 */
export async function runVerify(opts: { host?: string; port?: number }): Promise<void> {
  const meta = readMeta();
  const host = opts.host ?? meta?.host ?? 'localhost';
  const port = opts.port ?? meta?.port ?? 14242;

  const result = await runPostInstallVerification(host, port);
  if (!result.allPassed) {
    process.exit(1);
  }
}
