import assert from 'node:assert/strict';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { spawnSync } from 'node:child_process';
import { evaluateSummary, launchGateCheck, summarizeBenchmark } from './performance-summary.js';

const repoRoot = process.cwd();
const scriptPath = path.join(repoRoot, 'scripts', 'performance-summary.js');

function sampleReport(overrides = {}) {
  return {
    startedAt: '2026-06-30T04:45:08.281Z',
    finishedAt: '2026-06-30T04:50:08.281Z',
    apiBase: 'https://api.example.com',
    config: {
      durationSeconds: 300,
      concurrency: 30,
      rampSeconds: 30,
      includeWrites: false,
      questionLimit: 20,
      timeoutMs: 15000,
      ...(overrides.config || {}),
    },
    summary: {
      requests: 12000,
      ok: 12000,
      errors: 0,
      errorRate: 0,
      throughputRps: 40,
      okThroughputRps: 40,
      latencyOk: {
        p50Ms: 35,
        p90Ms: 120,
        p95Ms: 180,
        p99Ms: 430,
        maxMs: 700,
        ...(overrides.latencyOk || {}),
      },
      ...(overrides.summary || {}),
    },
  };
}

function runScript(report, args = []) {
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tiku-perf-summary-'));
  const inputPath = path.join(tempDir, 'report.json');
  fs.writeFileSync(inputPath, JSON.stringify(report, null, 2), 'utf8');
  const result = spawnSync(process.execPath, [scriptPath, '--input', inputPath, '--json', ...args], {
    cwd: repoRoot,
    encoding: 'utf8',
  });
  const payload = JSON.parse(result.stdout || '{}');
  fs.rmSync(tempDir, { recursive: true, force: true });
  return { ...result, payload };
}

const summary = summarizeBenchmark(sampleReport());
assert.deepEqual(
  {
    errors: summary.errors,
    errorRate: summary.errorRate,
    p95Ms: summary.p95Ms,
    p99Ms: summary.p99Ms,
    concurrency: summary.concurrency,
    durationSeconds: summary.durationSeconds,
    includeWrites: summary.includeWrites,
  },
  {
    errors: 0,
    errorRate: 0,
    p95Ms: 180,
    p99Ms: 430,
    concurrency: 30,
    durationSeconds: 300,
    includeWrites: false,
  },
);

const passingEvaluation = evaluateSummary(summary);
assert.equal(passingEvaluation.status, 'pass');
assert.deepEqual(launchGateCheck(passingEvaluation).summary, {
  errors: 0,
  errorRate: 0,
  p95Ms: 180,
  p99Ms: 430,
  concurrency: 30,
  durationSeconds: 300,
  includeWrites: false,
});

const okRun = runScript(sampleReport());
assert.equal(okRun.status, 0, `passing report should exit 0: ${okRun.stdout} ${okRun.stderr}`);
assert.equal(okRun.payload.evaluation?.status, 'pass');

const slowRun = runScript(sampleReport({ latencyOk: { p95Ms: 301 } }));
assert.notEqual(slowRun.status, 0, 'slow report should fail');
assert.equal(slowRun.payload.evaluation?.status, 'fail');
assert.ok(
  slowRun.payload.evaluation?.failures?.some(item => item.includes('p95Ms expected <= 300')),
  'slow report should explain p95 threshold failure',
);

const writeRun = runScript(sampleReport({ config: { includeWrites: true } }));
assert.notEqual(writeRun.status, 0, 'write benchmark should fail read-path gate');
assert.ok(
  writeRun.payload.evaluation?.failures?.some(item => item.includes('includeWrites expected false')),
  'write benchmark should explain includeWrites failure',
);

const allowedWriteRun = runScript(sampleReport({ config: { includeWrites: true } }), [
  '--allow-writes',
  '--min-duration-seconds=60',
  '--min-concurrency=30',
  '--max-p95-ms=500',
  '--max-p99-ms=1200',
]);
assert.equal(allowedWriteRun.status, 0, `allowed write report should exit 0: ${allowedWriteRun.stdout} ${allowedWriteRun.stderr}`);
assert.equal(allowedWriteRun.payload.evaluation?.status, 'pass');
assert.equal(allowedWriteRun.payload.evaluation?.options?.allowWrites, true);
assert.equal(allowedWriteRun.payload.launchGateCheck, undefined);
assert.equal(allowedWriteRun.payload.capacityObservation?.id, 'performance.api-real-data-mixed');
assert.equal(allowedWriteRun.payload.capacityObservation?.summary?.includeWrites, true);

console.log('[PASS] performance summary');
