#!/usr/bin/env node
import { spawnSync } from 'node:child_process';
import { existsSync } from 'node:fs';
import { resolveNatsServer, readNatsServerVersion } from './lib/nats-server-tool.mjs';

const json = process.argv.includes('--json');
const mode = process.argv.includes('--standalone')
  ? 'standalone'
  : process.argv.includes('--hivecast')
    ? 'hivecast'
    : process.argv.includes('--all')
      ? 'all'
      : 'base';

function check(name, ok, details = {}) {
  return { name, ok, ...details };
}

function run(command, args) {
  const result = spawnSync(command, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
  if (result.error) return { ok: false, error: result.error.message };
  if (result.status !== 0) return { ok: false, error: `${command} exited ${result.status}`, stderr: result.stderr.trim() };
  return { ok: true, stdout: result.stdout.trim(), stderr: result.stderr.trim() };
}

function major(version) {
  return Number(String(version).split('.')[0] ?? 0);
}

function findBrowser() {
  if (process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE && existsSync(process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE)) {
    return { path: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE, source: 'PLAYWRIGHT_CHROMIUM_EXECUTABLE' };
  }
  for (const path of ['/usr/bin/google-chrome', '/usr/bin/google-chrome-stable', '/usr/bin/chromium', '/usr/bin/chromium-browser']) {
    if (existsSync(path)) return { path, source: 'system' };
  }
  return null;
}

const checks = [];

const nodeVersion = process.versions.node;
checks.push(check('node', major(nodeVersion) >= 22, {
  version: nodeVersion,
  required: '22+',
  fix: 'Install Node.js 22 or newer.',
}));

const pnpm = run('pnpm', ['--version']);
checks.push(check('pnpm', pnpm.ok && major(pnpm.stdout) >= 10, {
  version: pnpm.ok ? pnpm.stdout : null,
  required: '10+',
  fix: 'Install pnpm 10: corepack enable && corepack prepare pnpm@10.29.3 --activate',
  error: pnpm.ok ? undefined : pnpm.error,
}));

let nats = null;
try {
  nats = resolveNatsServer();
  checks.push(check('nats-server', Boolean(nats), {
    path: nats?.path ?? null,
    source: nats?.source ?? null,
    version: nats ? readNatsServerVersion(nats.path) : null,
    requiredFor: 'pnpm demo:standalone',
    fix: 'Run pnpm setup:nats, or install NATS Server and put nats-server on PATH.',
  }));
} catch (error) {
  checks.push(check('nats-server', false, {
    error: error instanceof Error ? error.message : String(error),
    requiredFor: 'pnpm demo:standalone',
    fix: 'Run pnpm setup:nats, or set MATRIX_NATS_SERVER to the nats-server binary.',
  }));
}

const browser = findBrowser();
checks.push(check('chromium', Boolean(browser), {
  path: browser?.path ?? null,
  source: browser?.source ?? null,
  requiredFor: 'live browser proof in pnpm prove:fresh-samples',
  fix: 'Run pnpm setup:browser, or set PLAYWRIGHT_CHROMIUM_EXECUTABLE to Chrome/Chromium.',
}));

const hivecastEnv = {
  MATRIX_CLOUD: Boolean(process.env.MATRIX_CLOUD),
  MATRIX_SPACE: Boolean(process.env.MATRIX_SPACE),
  MATRIX_API_KEY: Boolean(process.env.MATRIX_API_KEY),
};
checks.push(check('hivecast-env', Object.values(hivecastEnv).every(Boolean), {
  present: hivecastEnv,
  requiredFor: 'live HiveCast server/browser samples in pnpm prove:fresh-samples',
  fix: 'Create a HiveCast API key, then export MATRIX_CLOUD, MATRIX_SPACE, and MATRIX_API_KEY.',
}));

const requiredByMode = {
  base: ['node', 'pnpm'],
  standalone: ['node', 'pnpm', 'nats-server'],
  hivecast: ['node', 'pnpm', 'chromium', 'hivecast-env'],
  all: ['node', 'pnpm', 'nats-server', 'chromium', 'hivecast-env'],
};
const requiredFailures = checks.filter((item) => requiredByMode[mode].includes(item.name) && !item.ok);
const proof = {
  ok: requiredFailures.length === 0,
  mode,
  checks,
};

if (json) {
  console.log(JSON.stringify(proof, null, 2));
} else {
  console.log(`Matrix SDK doctor mode: ${mode}`);
  for (const item of checks) {
    const required = requiredByMode[mode].includes(item.name);
    const mark = item.ok ? 'ok' : required ? 'missing' : 'optional-missing';
    console.log(`${mark} ${item.name}${item.version ? ` (${item.version})` : ''}${item.path ? ` at ${item.path}` : ''}`);
    if (!item.ok) console.log(`   fix: ${item.fix}`);
  }
}

process.exit(proof.ok ? 0 : 1);
