#!/usr/bin/env node
// Read N tracker files passed as args (shell-expanded glob), extract rows from
// each file's "## Fix Application Log" section, aggregate by
// phase × domain × decision × applied_by, print a summary table.
//
// Usage:
//   node framework/scripts/analyze-fix-application.js docs/references/trackers/*.md
//   node framework/scripts/analyze-fix-application.js path/to/tracker1.md path/to/tracker2.md
//
// Schema (must match framework/.claude/skills/new/SKILL.md "Fix Application Log Schema"):
//   <phase> | <domain> | est_lines=<n> | decision=<...> | applied_by=<...> | <key=val>...

'use strict';
const fs = require('fs');
const path = require('path');

const args = process.argv.slice(2).filter((a) => !a.startsWith('-'));
if (args.length === 0) {
  console.error('Usage: analyze-fix-application.js <tracker-file>...');
  console.error('Pass shell-expanded glob, e.g. docs/references/trackers/*.md');
  process.exit(2);
}

const SECTION_RE = /^##\s+Fix Application Log\s*$/i;
const ROW_RE = /^([\w.]+)\s*\|\s*([\w-]+)\s*\|\s*est_lines=(\d+)\s*\|\s*decision=([\w-]+)\s*\|\s*applied_by=([\w-]+)(?:\s*\|\s*(.*))?$/;

const buckets = new Map(); // key = "phase|domain|decision|applied_by" → { count, est_sum, est_n }
let totalRows = 0;
let filesParsed = 0;
let filesSkippedNoSection = 0;

for (const arg of args) {
  let content;
  try {
    content = fs.readFileSync(arg, 'utf8');
  } catch (err) {
    console.error(`skip ${arg}: ${err.message}`);
    continue;
  }
  filesParsed += 1;

  const lines = content.split(/\r?\n/);
  let inSection = false;
  let sawSection = false;
  for (const line of lines) {
    if (SECTION_RE.test(line)) {
      inSection = true;
      sawSection = true;
      continue;
    }
    if (inSection && /^##\s+\S/.test(line)) {
      // next H2 section starts — stop
      inSection = false;
      continue;
    }
    if (!inSection) continue;
    const m = line.match(ROW_RE);
    if (!m) continue;
    const [, phase, domain, estLinesStr, decision, appliedBy] = m;
    const key = `${phase}|${domain}|${decision}|${appliedBy}`;
    const est = parseInt(estLinesStr, 10);
    const bucket = buckets.get(key) || { count: 0, estSum: 0, estN: 0 };
    bucket.count += 1;
    if (est > 0) {
      bucket.estSum += est;
      bucket.estN += 1;
    }
    buckets.set(key, bucket);
    totalRows += 1;
  }
  if (!sawSection) filesSkippedNoSection += 1;
}

const rows = [];
for (const [key, b] of buckets) {
  const [phase, domain, decision, appliedBy] = key.split('|');
  const avgLines = b.estN > 0 ? (b.estSum / b.estN).toFixed(1) : '-';
  const pct = totalRows > 0 ? ((b.count / totalRows) * 100).toFixed(1) + '%' : '-';
  rows.push({ phase, domain, decision, appliedBy, count: b.count, avgLines, pct });
}
rows.sort((a, b) => a.phase.localeCompare(b.phase) || b.count - a.count);

const headers = ['Phase', 'Domain', 'Decision', 'Applied-by', 'Count', 'Avg-Lines', 'Pct-Total'];
const widths = headers.map((h, i) => {
  const colKey = ['phase', 'domain', 'decision', 'appliedBy', 'count', 'avgLines', 'pct'][i];
  return Math.max(h.length, ...rows.map((r) => String(r[colKey]).length));
});

function fmtRow(cells) {
  return cells.map((c, i) => String(c).padEnd(widths[i])).join('  ');
}

console.log(fmtRow(headers));
console.log(widths.map((w) => '-'.repeat(w)).join('  '));
for (const r of rows) {
  console.log(fmtRow([r.phase, r.domain, r.decision, r.appliedBy, r.count, r.avgLines, r.pct]));
}

console.log('');
console.log(`Files parsed: ${filesParsed}  |  Files w/o log section: ${filesSkippedNoSection}  |  Rows: ${totalRows}`);

// Flag candidate violations: inline apply on doc/security/migration domains
const violationRows = rows.filter(
  (r) =>
    r.appliedBy === 'orchestrator' &&
    (r.domain === 'doc' || r.domain === 'codex-security' || r.domain.startsWith('migration'))
);
if (violationRows.length > 0) {
  console.log('');
  console.log('⚠  Candidate violations (inline apply on domain-override domains):');
  for (const r of violationRows) {
    console.log(`   ${r.phase} | ${r.domain} | applied_by=${r.appliedBy} | count=${r.count}`);
  }
}
