#!/usr/bin/env node
/**
 * Brain governance controller C6 — chain-map sync checker.
 * Verifies tools/observer-chain-map.json against the L1-L13 table in
 * docs/routing-off-phase.md. Sync is checked by L-number sets (both
 * directions), not by node names — node_chosen values (skill-id) differ
 * from the human display names in the .md table. Pure fs/regex, no LLM.
 */
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

const __dirname = dirname(fileURLToPath(import.meta.url));
const MD_PATH = join(__dirname, '..', 'docs', 'routing-off-phase.md');
const JSON_PATH = join(__dirname, 'observer-chain-map.json');

/** Extract the set of L-numbers ("L1".."L13") from the routing-off-phase.md table. */
export function parseChainsFromMd(md) {
  const set = new Set();
  for (const line of md.split(/\r?\n/)) {
    const m = /^\|\s*(L\d+)\s*\|/.exec(line.trim());
    if (m) set.add(m[1]);
  }
  return set;
}

/** Compare JSON L-numbers against the md set, both directions. */
export function checkSync(jsonMap, mdSet) {
  const jsonSet = new Set();
  for (const [node, chains] of Object.entries(jsonMap)) {
    if (node === '_note') continue;
    if (Array.isArray(chains)) for (const c of chains) jsonSet.add(c);
  }
  const jsonOnly = [...jsonSet].filter((c) => !mdSet.has(c)); // ссылки на несуществующие L
  const mdOnly = [...mdSet].filter((c) => !jsonSet.has(c)); // потерянные цепочки
  return { ok: jsonOnly.length === 0 && mdOnly.length === 0, jsonOnly, mdOnly };
}

/** CLI entry — exit 1 on drift with a human-readable message. */
function main() {
  const md = readFileSync(MD_PATH, 'utf8');
  const jsonMap = JSON.parse(readFileSync(JSON_PATH, 'utf8'));
  const mdSet = parseChainsFromMd(md);
  if (mdSet.size === 0) {
    console.error(
      '[chain-map-checker] не нашёл ни одной L-строки в routing-off-phase.md — формат таблицы изменился?'
    );
    process.exit(1);
  }
  const res = checkSync(jsonMap, mdSet);
  if (res.ok) {
    console.log(`[chain-map-checker] OK — ${mdSet.size} chains in sync`);
    process.exit(0);
  }
  console.error('[chain-map-checker] дрейф маппинга chain-map <-> routing-off-phase.md:');
  if (res.jsonOnly.length)
    console.error(`  JSON ссылается на отсутствующие в .md цепочки: ${res.jsonOnly.join(', ')}`);
  if (res.mdOnly.length)
    console.error(
      `  В .md есть цепочки без записи в JSON: ${res.mdOnly.join(', ')} — добавьте узлы в tools/observer-chain-map.json`
    );
  process.exit(1);
}

if (process.argv[1]?.endsWith('observer-chain-map-checker.mjs')) {
  main();
}
