// Copyright (c) 2026 defconxt. All rights reserved.
// Licensed under AGPL-3.0 — see LICENSE file for details.

/**
 * NERF Benchmark — Report generation (JSON + Markdown with gap analysis).
 */

import { ALL_BASELINES } from './baselines.js';
import { reportToDict } from './runner.js';

export function generateJsonReport(report, solverName = '') {
  const data = reportToDict(report);
  data.metadata = { generated_at: new Date().toISOString(), solver: solverName };
  data.baselines = {};
  for (const bl of ALL_BASELINES) {
    data.baselines[bl.name] = {
      overall_pct: bl.overallPct,
      overall_passed: bl.overallPassed,
      overall_total: bl.overallTotal,
      level_pct: Object.fromEntries(Object.entries(bl.levelPct).map(([k, v]) => [String(k), v])),
      median_cost_usd: bl.medianCostUsd,
      source: bl.source,
    };
  }
  data.gap_analysis = {};
  for (const bl of ALL_BASELINES) {
    data.gap_analysis[bl.name] = {
      overall_delta: Math.round((report.passRate - bl.overallPct) * 10) / 10,
    };
  }
  return JSON.stringify(data, null, 2);
}

function medianCost(report) {
  const costs = report.results.map((r) => r.solverResult.apiCostUsd).sort((a, b) => a - b);
  if (!costs.length) return 0;
  const mid = Math.floor(costs.length / 2);
  return costs.length % 2 === 0 ? (costs[mid - 1] + costs[mid]) / 2 : costs[mid];
}

export function generateMarkdownReport(report, solverName = '') {
  const lines = [];
  lines.push('# NERF Benchmark Report', '');
  lines.push(`**Generated:** ${new Date().toISOString().slice(0, 16).replace('T', ' ')} UTC`);
  lines.push(`**Solver:** ${solverName}`, '');
  lines.push('## Summary', '');
  lines.push('| Metric | Value |', '|--------|-------|');
  lines.push(`| Total benchmarks | ${report.total} |`);
  lines.push(`| Passed | ${report.passed} |`);
  lines.push(`| Failed | ${report.failed} |`);
  lines.push(`| Skipped (errors) | ${report.skipped} |`);
  lines.push(`| **Pass rate** | **${report.passRate.toFixed(1)}%** |`);
  lines.push(`| Total duration | ${report.durationS.toFixed(1)}s |`);
  lines.push(`| Total cost | $${report.totalCostUsd.toFixed(4)} |`, '');

  if (ALL_BASELINES.length > 0) {
    lines.push('## Gap Analysis vs Competitors', '');
    lines.push('| System | Overall | Median Cost |');
    lines.push('|--------|---------|-------------|');
    const mc = medianCost(report);
    lines.push(`| **NERF** | **${report.passRate.toFixed(1)}%** | $${mc.toFixed(2)} |`);
    for (const bl of ALL_BASELINES) {
      const cost = bl.medianCostUsd ? `$${bl.medianCostUsd.toFixed(2)}` : '—';
      lines.push(`| ${bl.name} | ${bl.overallPct.toFixed(1)}% | ${cost} |`);
    }
    lines.push('');
  }

  // Results by difficulty level
  const byLevel = report.passRateByLevel();
  lines.push('## Results by Difficulty Level', '');
  for (const level of Object.keys(byLevel).sort()) {
    const lr = report.results.filter((r) => r.config.level === parseInt(level, 10));
    const p = lr.filter((r) => r.passed).length;
    const pct = lr.length ? (p / lr.length) * 100 : 0;
    const label = { 1: 'Easy', 2: 'Medium', 3: 'Hard' }[level] || `L${level}`;
    lines.push(`### Level ${level} — ${label} (${p}/${lr.length} = ${pct.toFixed(1)}%)`, '');
    lines.push('| Benchmark | Tags | Result | Duration | Cost |');
    lines.push('|-----------|------|--------|----------|------|');
    for (const r of lr.sort((a, b) => a.config.dirName.localeCompare(b.config.dirName))) {
      let status = r.passed ? '✅ PASS' : '❌ FAIL';
      if (r.solverResult.error) status = '⚠️ ERROR';
      lines.push(`| ${r.config.dirName} | ${r.config.tags.join(', ')} | ${status} | ${r.solverResult.durationS.toFixed(1)}s | $${r.solverResult.apiCostUsd.toFixed(4)} |`);
    }
    lines.push('');
  }

  // Tag-aware reporting
  const byTag = report.resultsByTag();
  if (Object.keys(byTag).length > 0) {
    lines.push('## Results by Vulnerability Category', '');
    lines.push('| Tag | Total | Passed | Rate |');
    lines.push('|-----|-------|--------|------|');
    for (const [tag, tagResults] of Object.entries(byTag).sort(([a], [b]) => a.localeCompare(b))) {
      const p = tagResults.filter(r => r.passed).length;
      const pct = tagResults.length ? (p / tagResults.length) * 100 : 0;
      lines.push(`| ${tag} | ${tagResults.length} | ${p} | ${pct.toFixed(1)}% |`);
    }
    lines.push('');
  }

  // Category breakdown (for NYU CTF and categorized benchmarks)
  const byCategory = {};
  for (const r of report.results) {
    const cat = r.config.category;
    if (cat) {
      if (!byCategory[cat]) byCategory[cat] = { total: 0, passed: 0 };
      byCategory[cat].total++;
      if (r.passed) byCategory[cat].passed++;
    }
  }
  if (Object.keys(byCategory).length > 0) {
    lines.push('## Results by Category', '');
    lines.push('| Category | Total | Passed | Rate |');
    lines.push('|----------|-------|--------|------|');
    for (const [cat, data] of Object.entries(byCategory).sort(([a],[b]) => a.localeCompare(b))) {
      const pct = data.total > 0 ? (data.passed / data.total * 100).toFixed(1) : '0.0';
      lines.push(`| ${cat} | ${data.total} | ${data.passed} | ${pct}% |`);
    }
    lines.push('');
  }

  return lines.join('\n');
}
