#!/usr/bin/env node

/**
 * audit-agents.mjs — AGENTS.md Execution Protocol Audit
 *
 * Checks:
 *  1. Task Tree exists (§1)
 *  2. Agent Package isolation requirements
 *  3. No XL Package (context budget forbids it)
 *  4. Injected Risks mechanism (§1e / §3b)
 *  5. Quality Gate completeness (§5)
 *
 * Usage:
 *   node scripts/audit-agents.mjs          ← standalone
 *   import { runAgentAudit } from './audit-agents.mjs'  ← via orchestrator
 */

import { fileURLToPath } from 'url';
import path from 'path';
import fs from 'fs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const WORKSPACE = path.resolve(__dirname, '..');
const SELF = process.argv[1].replace(/\\/g, '/');

/**
 * @typedef {Object} CheckResult
 * @property {string} id
 * @property {string} name
 * @property {'PASS'|'WARN'|'FAIL'} status
 * @property {string} evidence
 * @property {string} [suggestion]
 */

/** @returns {CheckResult[]} */
export function runAgentAudit(workspaceDir) {
  const root = workspaceDir || WORKSPACE;
  const checks = [];

  // ---- Helper ----
  function readAgents() {
    const p = path.join(root, 'AGENTS.md');
    if (!fs.existsSync(p)) return null;
    return fs.readFileSync(p, 'utf8');
  }

  function check(prefix, id, name, condition, evidence, suggestion) {
    checks.push({
      id: `${prefix}-${id}`,
      name,
      status: condition ? 'PASS' : 'FAIL',
      evidence: condition ? evidence : `File found but missing: ${evidence}`,
      ...(condition ? {} : { suggestion: suggestion || `Ensure §${id} is properly defined in AGENTS.md` }),
    });
  }

  function warn(prefix, id, name, evidence, suggestion) {
    checks.push({
      id: `${prefix}-${id}`,
      name,
      status: 'WARN',
      evidence,
      suggestion,
    });
  }

  // ---- Read AGENTS.md ----
  const agents = readAgents();
  if (!agents) {
    checks.push({
      id: 'AG-001',
      name: 'AGENTS.md exists',
      status: 'FAIL',
      evidence: 'AGENTS.md not found in workspace root',
      suggestion: 'Create AGENTS.md with the Execution Protocol',
    });
    return checks;
  }
  checks.push({
    id: 'AG-001',
    name: 'AGENTS.md exists',
    status: 'PASS',
    evidence: `AGENTS.md found (${agents.length} bytes)`,
  });

  // ---- §0 Complexity Classification ----
  const hasClassify = /###\s*0\.\s*Complexity Classification/.test(agents);
  check('AG', '0', '§0 Complexity Classification defined', hasClassify,
    'Found "### 0. Complexity Classification" with Simple/Complex criteria',
    'Add "### 0. Complexity Classification" with Simple→Direct / Complex→Task Tree decision rules');

  // Detect if the "if uncertain → treat as Complex" rule exists
  const hasUncertainRule = /if uncertain → treat as Complex/i.test(agents) || /if uncertain.*complex/i.test(agents);
  check('AG', '0b', '§0 Uncertainty fallback ("if uncertain → treat as Complex")', hasUncertainRule,
    'Uncertainty fallback rule found',
    'Add decision rule: "if uncertain → treat as Complex"');

  // ---- §1 Task Tree ----
  const hasTaskTree = /###\s*1\.\s*Task Tree/.test(agents);
  check('AG', '1', '§1 Task Tree Construction defined', hasTaskTree,
    'Found "### 1. Task Tree Construction" with Task Tree definition',
    'Add "### 1. Task Tree Construction" defining the execution tree');

  // Task Tree Quality Gate (7 checks)
  const hasTaskTreeGate = /Task Tree Quality Gate/.test(agents);
  check('AG', '1f', '§1f Task Tree Quality Gate (7 checks)', hasTaskTreeGate,
    'Found Task Tree Quality Gate with 7 verification items',
    'Add §1f Quality Gate checklist (Root Task / No orphan / No circular / No XL / No unjust serial / Risks populated / No human dep)');

  // ---- §2 PLAN ----
  const hasPlan = /###\s*2\.\s*Planning Protocol/.test(agents);
  check('AG', '2', '§2 Planning Protocol defined', hasPlan,
    'Found "### 2. Planning Protocol" with Goal/Subtasks/Risks/Verify',
    'Add "### 2. Planning Protocol" section');

  // ---- §3 Pre-flight ----
  const hasPreflight = /###\s*3\.\s*Pre-flight/.test(agents);
  check('AG', '3', '§3 Pre-flight Check defined', hasPreflight,
    'Found "### 3. Pre-flight Check" with Dependency Scan / Learning Context / Domain Checklists',
    'Add "### 3. Pre-flight Check" section');

  // 3a Dependency Scan
  const hasDepScan = /####\s*3a\.\s*Dependency Scan/.test(agents);
  check('AG', '3a', '§3a Dependency Scan defined', hasDepScan,
    'Found §3a Dependency Scan',
    'Add §3a Dependency Scan (files/tables, dependencies, blast radius)');

  // 3b Learning Context Injector
  const hasLearningCtx = /####\s*3b\.\s*Learning Context Injector/.test(agents);
  check('AG', '3b', '§3b Learning Context Injector (3 searches)', hasLearningCtx,
    'Found §3b Learning Context Injector with 3 mandatory searches',
    'Add §3b with 3 searches: similar failures, best practices, playbooks');

  // 3c Domain Checklists
  const hasDomainChecklists = /####\s*3c\.\s*Domain Checklist Injection/.test(agents);
  check('AG', '3c', '§3c Domain Checklists with ⚠️ Hard Rules', hasDomainChecklists,
    'Found §3c Domain Checklist Injection with SQL/JS/Next.js/Backend/Generator/Release checklists',
    'Add §3c with at least SQL, JS/TS, Next.js, Backend, Generator, Release checklists');

  // Hard Rules exist
  const hardRuleCount = (agents.match(/⚠️\s*HARD RULE/g) || []).length;
  warn('AG', '3c-hard', `§3c Hard Rules count: ${hardRuleCount} (target: ≥5)`,
    `Found ${hardRuleCount} ⚠️ HARD RULE markers`,
    'Promote recurring patterns to Hard Rules. Target ≥5.');

  // ---- §4 Failure Replanning ----
  const hasReplan = /###\s*4\.\s*Failure Replanning Protocol/.test(agents);
  check('AG', '4', '§4 Failure Replanning Protocol defined', hasReplan,
    'Found "### 4. Failure Replanning Protocol" with local/structural replan logic',
    'Add "### 4. Failure Replanning Protocol"');

  // ---- §5 Verification Protocol ----
  const hasVerification = /###\s*5\.\s*Verification Protocol/.test(agents);
  check('AG', '5', '§5 Verification Protocol defined', hasVerification,
    'Found "### 5. Verification Protocol" with Build/Tests/Lint/Regression/Manual checks',
    'Add "### 5. Verification Protocol" with the verification block format');

  // Quality Gate in Verification
  const hasQualityGate = /Pre-flight Compliance Check/.test(agents) || /Quality Gate/.test(agents);
  check('AG', '5b', '§5 Pre-flight Compliance / Quality Gate', hasQualityGate,
    'Found "Pre-flight Compliance Check" with 5 mandatory gates',
    'Add Quality Gate checklist within §5: PLAN has Injected Risks, ≥2 sources searched, domain checklist, reflection, 7-field reflection');

  // ---- §6 Governance Compliance ----
  const hasGovernance = /###\s*6\.\s*Governance Compliance/.test(agents);
  check('AG', '6', '§6 Governance Compliance defined', hasGovernance,
    'Found "### 6. Governance Compliance" with State Machine / Heartbeat / Quality Gate',
    'Add "### 6. Governance Compliance" referencing GOVERNANCE.md');

  // ---- §7 Auto-Capture ----
  const hasAutoCapture = /###\s*7\.\s*Auto-Capture Trigger/.test(agents);
  check('AG', '7', '§7 Auto-Capture Trigger defined', hasAutoCapture,
    'Found "### 7. Auto-Capture Trigger" with T1-T7 trigger conditions',
    'Add "### 7. Auto-Capture Trigger" with 7 trigger conditions and skip rules');

  // ---- Learning Loop ----
  const hasLearningLoop = /## Learning Loop/.test(agents);
  check('AG', 'LL', 'Learning Loop (🔄) defined', hasLearningLoop,
    'Found "## Learning Loop 🔄" with Loop Architecture / Promotion Rules / Reflection Quality Gate / Storage Locations',
    'Add "## Learning Loop 🔄" section');

  // Promotion Rules (1→2→3→4→5)
  const hasPromotion = /Promotion Rules/.test(agents) && /1st.*Reflection/.test(agents) && /5th.*Hard Rule/.test(agents);
  check('AG', 'LL-promo', 'Promotion Rules (1→2→3→4→5 appearances)', hasPromotion,
    'Found Promotion Rules chart with 1st=Reflection through 5th=Hard Rule',
    'Add Promotion Rules table mapping appearance count to promotion destination');

  // ---- Context Budget ----
  const hasBudget = /## Agent Package Context Budget/.test(agents);
  check('AG', 'CB', 'Agent Package Context Budget defined', hasBudget,
    'Found "## Agent Package Context Budget ⚠️ HARD RULE" with size→token map',
    'Add "## Agent Package Context Budget" section');

  // No XL
  const forbidsXL = /XL.*FORBIDDEN/.test(agents) || /XL.*❌/.test(agents);
  check('AG', 'CB-noxl', 'XL Package explicitly forbidden', forbidsXL,
    'Found "XL | ❌ FORBIDDEN" in Context Budget table',
    'Add "XL | ❌ FORBIDDEN" row to the Size→Token Budget Mapping table');

  // Input Size Pre-check
  const hasPrecheck = /Input Size Pre-check/.test(agents);
  check('AG', 'CB-precheck', 'Input Size Pre-check (Context Budget Declaration)', hasPrecheck,
    'Found "Input Size Pre-check" with Context Budget Declaration template',
    'Add "Input Size Pre-check" section with file inventory / token estimate / budget check');

  // ---- Cross-reference integrity ----
  const refsGovernance = (agents.match(/GOVERNANCE\.md/g) || []).length;
  warn('AG', 'XR-gov', `Cross-references to GOVERNANCE.md: ${refsGovernance} (target: ≥3)`,
    `Found ${refsGovernance} references to GOVERNANCE.md`,
    'Add cross-references from AGENTS.md to GOVERNANCE.md in §6');

  const refsPortfolio = (agents.match(/PORTFOLIO\.md/g) || []).length;
  warn('AG', 'XR-port', `Cross-references to PORTFOLIO.md: ${refsPortfolio} (target: ≥1)`,
    `Found ${refsPortfolio} references to PORTFOLIO.md`,
    'Add cross-reference to PORTFOLIO.md in §6e Reference section');

  // ---- Injected Risks (target check) ----
  const hasInjectedRisks = /Injected Risks/.test(agents);
  check('AG', 'IR', 'Injected Risks mechanism defined', hasInjectedRisks,
    'Found "### Injected Risks" / "### Per-Task Injected Risks"',
    'Add "### Injected Risks (from Learning Context)" format in §1e and §3b');

  // ---- Summary ----
  const passCount = checks.filter(c => c.status === 'PASS').length;
  const warnCount = checks.filter(c => c.status === 'WARN').length;
  const failCount = checks.filter(c => c.status === 'FAIL').length;
  checks.push({
    id: 'AG-SUMMARY',
    name: `Summary — ${passCount} PASS / ${warnCount} WARN / ${failCount} FAIL`,
    status: failCount > 0 ? 'FAIL' : warnCount > 0 ? 'WARN' : 'PASS',
    evidence: `${passCount} passed, ${warnCount} warnings, ${failCount} failures`,
  });

  return checks;
}

// ---- Standalone runner ----
if (SELF.endsWith('/audit-agents.mjs') || SELF.endsWith('\\audit-agents.mjs')) {
  const results = runAgentAudit(WORKSPACE);
  console.log(`\n=== AGENTS.md Audit ===\n`);
  for (const r of results) {
    const icon = r.status === 'PASS' ? '✅' : r.status === 'WARN' ? '⚠️' : '❌';
    console.log(`  ${icon} [${r.id}] ${r.name}`);
    console.log(`     ${r.evidence}`);
    if (r.suggestion) console.log(`     → ${r.suggestion}`);
    console.log();
  }
}
