#!/usr/bin/env tsx
/**
 * count-roadmap-progress.ts — parse the v3 cross-repo UX roadmap doc and
 * regenerate the "§11.2 Progress at a glance" block with live counts.
 *
 * Usage:
 *   pnpm dlx tsx scripts/count-roadmap-progress.ts \
 *     docs/UI_ROADMAP_2026_V3_CROSS_REPO.md
 *
 * Behaviour:
 *   - Reads the given doc.
 *   - Counts `- [ ]` (open) and `- [x]` / `- [X]` (closed) checkboxes in each
 *     §11.x sub-section by parsing `### 11.N Wave …` headings.
 *   - Rewrites the fenced block inside `### 11.2 Progress at a glance`
 *     in-place so the visible counters match reality.
 *   - Also rewrites the `· `0 / N`` suffix on every `### 11.x Wave …`
 *     heading so per-wave totals stay accurate.
 *
 * Idempotent: re-running with no checkbox changes is a no-op.
 * Exit codes: 0 ok, 1 doc not found, 2 expected sections missing.
 *
 * Authored: Wave 8.A.7 of v3.2 roadmap.
 */
import { readFileSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';

const docPath = resolve(process.argv[2] ?? 'docs/UI_ROADMAP_2026_V3_CROSS_REPO.md');

let src: string;
try {
  src = readFileSync(docPath, 'utf8');
} catch {
  console.error(`[count-roadmap-progress] cannot read ${docPath}`);
  process.exit(1);
}

interface Section {
  /** Heading label (e.g. "Wave 8 Rollout"). */
  label: string;
  /** Regex matching the `### 11.x …` heading. */
  headingRe: RegExp;
  /** Regex matching the next `### 11.x …` heading (acts as end-marker). */
  nextHeadingRe: RegExp;
}

const sections: Section[] = [
  { label: 'Wave 8 Rollout', headingRe: /^### 11\.3 Wave 8 .*$/m, nextHeadingRe: /^### 11\.4 /m },
  { label: 'Wave 9 Data', headingRe: /^### 11\.4 Wave 9 .*$/m, nextHeadingRe: /^### 11\.5 /m },
  { label: 'Wave 10 Shells', headingRe: /^### 11\.5 Wave 10 .*$/m, nextHeadingRe: /^### 11\.6 /m },
  {
    label: 'Wave 11 Adaptive',
    headingRe: /^### 11\.6 Wave 11 .*$/m,
    nextHeadingRe: /^### 11\.7 /m,
  },
  { label: 'Wave 12 Mobile', headingRe: /^### 11\.7 Wave 12 .*$/m, nextHeadingRe: /^### 11\.8 /m },
  {
    label: 'Wave 13 Futurism',
    headingRe: /^### 11\.8 Wave 13 .*$/m,
    nextHeadingRe: /^### 11\.9 /m,
  },
  {
    label: 'Cross-cutting',
    headingRe: /^### 11\.9 Cross-cutting .*$/m,
    nextHeadingRe: /^### 11\.10 /m,
  },
  { label: 'Magnet demos', headingRe: /^### 11\.10 .*$/m, nextHeadingRe: /^---\s*$/m },
];

function sliceSection(text: string, start: RegExp, end: RegExp): string | null {
  const startMatch = start.exec(text);
  if (!startMatch) return null;
  const after = text.slice(startMatch.index);
  const endMatch = end.exec(after);
  return endMatch ? after.slice(0, endMatch.index) : after;
}

function countChecks(block: string): { open: number; done: number } {
  const open = (block.match(/^- \[ \]/gm) ?? []).length;
  const done = (block.match(/^- \[[xX]\]/gm) ?? []).length;
  return { open, done };
}

function bar(done: number, total: number, width = 10): string {
  if (total === 0) return '⬛'.repeat(width);
  const filled = Math.round((done / total) * width);
  return '🟩'.repeat(filled) + '⬛'.repeat(width - filled);
}

function pct(done: number, total: number): string {
  if (total === 0) return '  0%';
  return `${String(Math.round((done / total) * 100)).padStart(3)}%`;
}

interface Tally {
  label: string;
  done: number;
  total: number;
}
const tallies: Tally[] = [];

let totalDone = 0;
let totalAll = 0;

for (const s of sections) {
  const block = sliceSection(src, s.headingRe, s.nextHeadingRe);
  if (block === null) {
    console.error(`[count-roadmap-progress] section not found: ${s.label}`);
    process.exit(2);
  }
  const { open, done } = countChecks(block);
  const total = open + done;
  tallies.push({ label: s.label, done, total });
  totalDone += done;
  totalAll += total;
}

// Build the new "§11.2 Progress at a glance" fenced block.
const lines: string[] = [];
lines.push(
  `TOTAL              ${String(totalDone).padStart(3)} / ${String(totalAll).padStart(3)}  ${bar(totalDone, totalAll)} ${pct(totalDone, totalAll)}`
);
lines.push('─'.repeat(45));
const labelWidth = Math.max(...tallies.map(t => t.label.length));
for (const t of tallies) {
  lines.push(
    `${t.label.padEnd(labelWidth)}  ${String(t.done).padStart(3)} / ${String(t.total).padStart(3)}  ${bar(t.done, t.total)} ${pct(t.done, t.total)}`
  );
}
const newBlock = lines.join('\n');

// Locate the existing fenced block inside §11.2 and replace its body.
const headerRe = /(### 11\.2 Progress at a glance\s*\n+```)([\s\S]*?)(```)/;
const headerMatch = src.match(headerRe);
if (!headerMatch) {
  console.error('[count-roadmap-progress] §11.2 fenced block not found');
  process.exit(2);
}
const replaced = src.replace(
  headerRe,
  (_full, open, _body, close) => `${open}\n${newBlock}\n${close}`
);

// Also rewrite the per-section `· \`N / M\`` suffix on §11.3 .. §11.10 headings.
let withSuffixes = replaced;
const headingSuffixMap: Array<[RegExp, Tally]> = [
  [/^(### 11\.3 Wave 8 — Unblock & rollout) · `[^`]*`$/m, tallies[0]!],
  [/^(### 11\.4 Wave 9 — Data, content, search) · `[^`]*`$/m, tallies[1]!],
  [/^(### 11\.5 Wave 10 — Product surfaces & shells) · `[^`]*`$/m, tallies[2]!],
  [/^(### 11\.6 Wave 11 — Adaptive \/ ambient \/ multimodal) · `[^`]*`$/m, tallies[3]!],
  [/^(### 11\.7 Wave 12 — Mobile · i18n · sustainability) · `[^`]*`$/m, tallies[4]!],
  [/^(### 11\.8 Wave 13 — Futurism layer) · `[^`]*`$/m, tallies[5]!],
  [/^(### 11\.9 Cross-cutting) · `[^`]*`$/m, tallies[6]!],
];
for (const [re, t] of headingSuffixMap) {
  withSuffixes = withSuffixes.replace(re, (_match, head) => `${head} · \`${t.done} / ${t.total}\``);
}

if (withSuffixes === src) {
  console.log('[count-roadmap-progress] up to date — no changes');
} else {
  writeFileSync(docPath, withSuffixes, 'utf8');
  console.log(
    `[count-roadmap-progress] rewrote §11.2 + per-wave headings  (${totalDone} / ${totalAll} done)`
  );
}
