#!/usr/bin/env node
/**
 * smoke-http/index.ts — Entry point.
 * parse args → validate → execute probes → print JSON report on stdout.
 */
import { readFileSync } from 'node:fs';
import { Command } from 'commander';
import { validateArgs } from './validate.js';
import { execute } from './execute.js';
import type { SmokeHttpOutput } from './types.js';

const program = new Command();

program
  .name('smoke-http')
  .description('HTTP smoke prober — fetches a list of URLs and reports pass/fail status codes')
  .option('--probes <json>', 'Inline JSON array of probes')
  .option('--probes-file <path>', 'Path to a JSON file containing the probes array')
  .option('--timeout-ms <ms>', 'Per-probe timeout', '5000')
  .option('--retries <n>', 'Retry attempts per probe', '10')
  .option('--retry-delay-ms <ms>', 'Base delay between retries', '500')
  .option('--follow-redirects <bool>', 'Follow 3xx redirects', 'true')
  .option('--concurrency <n>', 'Parallel probe count', '4')
  .parse(process.argv);

const opts = program.opts();

function fail(errors: string[], exitCode = 1): never {
  const output: SmokeHttpOutput = {
    success: false,
    command: 'smoke-http',
    data: { totalProbes: 0, passed: 0, failed: 0, allPassed: false },
    report: null,
    errors,
    warnings: [],
    nextSteps: [],
  };
  console.log(JSON.stringify(output, null, 2));
  process.exit(exitCode);
}

let probesRaw: unknown;
if (opts.probes && opts.probesFile) {
  fail(['pass either --probes (inline) or --probes-file, not both.']);
}
if (opts.probes) {
  try {
    probesRaw = JSON.parse(opts.probes);
  } catch (err) {
    fail([`--probes is not valid JSON: ${err instanceof Error ? err.message : String(err)}`]);
  }
} else if (opts.probesFile) {
  try {
    probesRaw = JSON.parse(readFileSync(opts.probesFile, 'utf8'));
  } catch (err) {
    fail([`Failed to read/parse --probes-file: ${err instanceof Error ? err.message : String(err)}`]);
  }
} else {
  fail(['Missing probes. Pass --probes <json> or --probes-file <path>.']);
}

const raw = {
  probes: probesRaw,
  timeoutMs: Number(opts.timeoutMs),
  retries: Number(opts.retries),
  retryDelayMs: Number(opts.retryDelayMs),
  followRedirects: opts.followRedirects !== 'false',
  concurrency: Number(opts.concurrency),
};

const validation = validateArgs(raw);
if (!validation.valid || !validation.args) {
  fail(validation.errors);
}

try {
  const report = await execute(validation.args!);
  const passed = report.results.filter((r) => r.status === 'pass').length;
  const failed = report.results.filter((r) => r.status === 'fail').length;
  const allPassed = failed === 0;

  const nextSteps: string[] = [];
  if (!allPassed) {
    nextSteps.push(
      `${failed} probe${failed > 1 ? 's' : ''} failed. Inspect the report and run fix-bug on the failing endpoint(s).`,
    );
    for (const r of report.results.filter((x) => x.status === 'fail')) {
      nextSteps.push(`  - ${r.method} ${r.url} expected ${r.expect} got ${r.actual ?? 'no response'}`);
    }
  } else {
    nextSteps.push(`All ${passed} probe(s) passed.`);
  }

  const output: SmokeHttpOutput = {
    success: true,
    command: 'smoke-http',
    data: {
      totalProbes: report.results.length,
      passed,
      failed,
      allPassed,
    },
    report,
    errors: [],
    warnings: [],
    nextSteps,
  };
  console.log(JSON.stringify(output, null, 2));
  process.exit(allPassed ? 0 : 1);
} catch (err) {
  const message = err instanceof Error ? err.message : String(err);
  fail([`Unexpected error during probe execution: ${message}`]);
}
