#!/usr/bin/env bun
/**
 * render_report.ts — 精简版综合报告渲染器（Bun TS）
 * 输出: nexify-corpora-report.html（自包含；仅 §4 三库总览 + §5 遗留路线）
 * 用法: bun render_report.ts [输出路径]
 *
 * 数据口径与 comparison/ 各报告一致（2026-09-03, extract_version=12, commit ead3674）：
 *  - codewhale: compare_versions.py v6→v12（cache-ead3674-v12.db）
 *  - Zed:       COMPARISON-zed-nexify-v11/v12
 *  - pdf-inspector: v12 冷扫实测（cache-pdf-inspector-65b7fa1-v12.db，与 v11 零差异）
 */
import { writeFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";

const HERE = dirname(fileURLToPath(import.meta.url));
const OUT = process.argv[2] ?? join(HERE, "nexify-corpora-report.html");

// ── 三库总览数据 ─────────────────────────────────────────────────────
// v11 → v12；b/a 数值，Δ 自动生成（千分位+单位）；thresh 为该格可接受波动（|Δ|≤thresh 标灰）；good: 向此方向移动 = 进化（绿）
const OVERVIEW = [
  { m: "形态", v: ["workspace · 21 crate · 1,976 文件", "workspace · 245 crate · 4,018 文件", "单 package + napi/wasm · 55 .rs"], good: "none" },
  { m: "节点 / edges", v: ["153,640 / 223,687", "209,822 / 308,854", "13,349 / 15,833"], good: "none" },
  { m: "冷建图", b: [33.5, 89.0, 1.5], a: [35.5, 89.8, 1.51], good: "down", unit: "s", thresh: [0.05, 1.0, 0.05] },
  { m: "resolve", b: [7.37, 40.1, 0.21], a: [7.52, 40.65, 0.2], good: "down", unit: "s", thresh: [0.05, 1.0, 0.05] },
  { m: "pending", b: [128392, 241473, 9028], a: [128392, 241473, 9028], good: "down" },
  { m: "INFERRED resolved", b: [21622, 31651, 603], a: [22451, 36151, 603], good: "up" },
  { m: "AMBIGUOUS", b: [252, 8104, 4], a: [252, 8104, 4], good: "down" },
  { m: "UNRESOLVED", b: [33953, 43398, 1553], a: [33124, 38898, 1553], good: "down" },
  { m: "跨文件绑定率（仅 .rs）", b: [38.7, 38.1, 39.1], a: [40.2, 43.5, 39.1], good: "up", valueUnit: "%", deltaUnit: "pp" },
] as { m: string; v?: [string, string, string]; b?: [number, number, number]; a?: [number, number, number]; good: "up" | "down" | "none"; unit?: "s"; valueUnit?: string; deltaUnit?: string; thresh?: [number, number, number] }[];

// ── 遗留与路线数据 ───────────────────────────────────────────────────
const BACKLOG = [
  ["#M4-post-7", "glob re-export 展开", "Zed", "4,500 恢复", "ok", "✅ 已交付（ead3674）"],
  ["#M4-post-10", "<code>use super::*</code> 透传 + <code>pub(crate) use</code> 垃圾导入", "Zed 残余 px 771 / div 97", "千级", "warn", "待派（建议下个）"],
  ["#M4-post-9", "单 package crate 根路径 + 模块级 re-export", "pdf-inspector", "233", "warn", "待派（与 post-10 部分同源）"],
  ["#M4-post-6", "夹具/假 crate 混入（test_fixture）", "Zed", "67+8 误绑", "warn", "待派（精度）"],
  ["#M4-post-8", "嵌套 fn 遮蔽", "Zed", "2 确证", "muted", "P4 小项"],
  ["P3", "测试双变体方法歧义（接收者消歧增强）", "Zed", "8,104 AMBIGUOUS", "muted", "低优先（安全弃绑）"],
  ["长期", "references 类型使用边 + 社区/枢纽榜", "graphify 对比", "—", "muted", "M5 候选"],
];

const css = `
  :root { --bg:#f6f7f9; --card:#ffffff; --ink:#1f2937; --muted:#6b7280; --line:#e5e7eb; --accent:#2563eb; --green:#16a34a; --red:#dc2626; --amber:#d97706; }
  * { box-sizing:border-box; margin:0; padding:0; }
  body { background:var(--bg); color:var(--ink); font:14px/1.6 -apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif; padding:32px 16px; }
  .wrap { max-width:960px; margin:0 auto; }
  header { background:linear-gradient(135deg,#1e3a8a,#2563eb); color:#fff; border-radius:14px; padding:22px 28px; margin-bottom:20px; }
  header h1 { font-size:20px; font-weight:700; margin-bottom:5px; }
  header p { opacity:.92; font-size:12.5px; }
  section { background:var(--card); border:1px solid var(--line); border-radius:12px; padding:20px 26px; margin-bottom:18px; }
  h2 { font-size:15.5px; margin:0 0 13px; padding-left:10px; border-left:4px solid var(--accent); }
  table { width:100%; border-collapse:collapse; font-size:13px; margin:8px 0 2px; }
  th, td { padding:7px 10px; text-align:right; border-bottom:1px solid var(--line); white-space:nowrap; }
  th:first-child, td:first-child { text-align:left; }
  thead th { background:#f1f5f9; font-weight:600; color:#334155; }
  tbody tr:hover { background:#f8fafc; }
  code { background:#f1f5f9; border:1px solid var(--line); border-radius:4px; padding:1px 5px; font-size:12px; font-family:ui-monospace,"SF Mono",Consolas,monospace; }
  .verdict { font-size:12.5px; margin:7px 0 0; color:#475569; }
  .green { color:var(--green); font-weight:600; } .red { color:var(--red); font-weight:600; } .gray { color:var(--muted); }
  .ok { color:var(--green); font-weight:600; } .warn { color:var(--amber); font-weight:600; } .muted { color:var(--muted); }
  .note { background:#fffbeb; border:1px solid #fde68a; border-radius:8px; padding:12px 14px; font-size:12.5px; color:#78350f; margin-top:13px; }
  footer { text-align:center; color:var(--muted); font-size:12px; padding:10px 0 4px; }
  .corpus-tag { display:inline-block; border-radius:6px; padding:1px 8px; font-size:11.5px; font-weight:600; color:#fff; }
  .tag-cw { background:#6366f1; } .tag-zed { background:#0ea5e9; } .tag-pdf { background:#f59e0b; }
`;

// Δ 文本：千分位 + 符号 + 单位
function fmtNum(v: number, suffix: string | undefined): string {
  const s = Number.isInteger(v) ? v.toLocaleString("en-US") : String(Math.round(v * 100) / 100);
  return `${s}${suffix ?? ""}`;
}
function fmtDelta(delta: number, suffix: string | undefined): string {
  if (delta === 0) return "0";
  const sign = delta > 0 ? "+" : "−";
  return `${sign}${fmtNum(Math.abs(delta), suffix)}`;
}

// Δ 着色：|Δ|≤thresh 视为测量噪声（灰）；否则 good=up 升为绿/降为红，good=down 反之
function clsFor(good: "up" | "down" | "none", delta: number, thresh: number): string {
  if (good === "none") return "";
  if (Math.abs(delta) <= thresh) return "gray";
  const better = good === "up" ? delta > 0 : delta < 0;
  return better ? "green" : "red";
}

const overviewRows = OVERVIEW.map((row) => {
  const thresh = row.thresh ?? [0.05, 0.05, 0.05];
  const tds = (row.v ?? ["", "", ""]).map((v, i) => {
    const num = row.b?.[i];
    if (num === undefined) return `<td>${v}</td>`;
    const delta = (row.a?.[i] ?? 0) - num;
    const cls = clsFor(row.good, delta, thresh[i]);
    const vu = row.valueUnit ?? row.unit ?? "";
    const du = row.deltaUnit ?? row.unit ?? "";
    return `<td class="${cls}">${fmtNum(num, vu)} → <b>${fmtNum(row.a![i], vu)}</b>（${fmtDelta(delta, du)}）</td>`;
  }).join("");
  return `<tr><td>${row.m}</td>${tds}</tr>`;
}).join("");

const backlogRows = BACKLOG.map(([id, item, src, size, kind, status]) =>
  `<tr><td><code>${id}</code></td><td style="text-align:left">${item}</td><td style="text-align:left">${src}</td><td>${size}</td><td class="${kind}">${status}</td></tr>`
).join("");

const html = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>nexify 三语料综合验证报告（总览 + 遗留路线）</title>
<style>${css}</style>
</head>
<body>
<div class="wrap">

<header>
  <h1>nexify 多语料综合验证报告 · codewhale × Zed × pdf-inspector</h1>
  <p>extract_version 12（commit ead3674）· 2026-09-03 · 数据源：compare_versions.py v6→v12 / COMPARISON-zed-v11/v12 / pdf-inspector v12 冷扫实测</p>
</header>

<section>
  <h2>1. 三库总览（并列）</h2>
  <table>
    <thead><tr><th>指标</th><th><span class="corpus-tag tag-cw">codewhale</span></th><th><span class="corpus-tag tag-zed">Zed</span></th><th><span class="corpus-tag tag-pdf">pdf-inspector</span></th></tr></thead>
    <tbody>${overviewRows}</tbody>
  </table>
  <p class="verdict">
    <b>色义：</b><span class="green">绿 = 进化</span>（耗时下降 / 召回上升 / 漏绑下降）；<span class="red">红 = 退化</span>；<span class="gray">灰 = 持平 / 未测</span>。
    v11 时三库绑定率恒稳 38–39%；v12 后 codewhale 40.2%、Zed 43.5%（+5.4pp）——glob 展开（#M4-post-7）把大批真调用从 UNRESOLVED 拉回 INFERRED，AMBIGUOUS 零变化。
    pdf-inspector v12 与 v11 零差异（单 package 无 glob 形态，glob 展开零影响，与 codewhale 零回退互证）。
    口径：绑定率 = resolved / (resolved + ambiguous + unresolved)；Zed 冷建图 v12 为 extract+resolve 合计；codewhale 冷建图 v12 为 06:17 重扫实测（extract 27.29s + resolve 8.08s，含 glob 索引 scan 期成本）。
  </p>
</section>

<section>
  <h2>2. 遗留与路线（按优先级）</h2>
  <table>
    <thead><tr><th>#</th><th>内容</th><th>来源</th><th>规模</th><th>状态</th></tr></thead>
    <tbody>${backlogRows}</tbody>
  </table>
  <div class="note">建议下派：#M4-post-10（Zed 残余 px 771 / div 97 主因，与 #M4-post-9 子机制 b 部分同源，可合并排期）。</div>
</section>

<footer>nexify v0.2.2 · extract_version 12（ead3674）· 2026-09-03 · 报告由 render_report.ts 渲染（bun render_report.ts 重新生成）</footer>

</div>
</body>
</html>`;

writeFileSync(OUT, html);
console.log(`rendered: ${OUT} (${(html.length / 1024).toFixed(1)} KB)`);