#!/usr/bin/env node
/*
  Generates an auditable map of privileged (onlyOwner) functions in Solidity.

  Purpose: make governance/privilege explicit and hard to accidentally expand.
  This is a documentation generator, not a security analyzer.

  - Scans contracts/** (recursive) for .sol files (excluding contracts/deprecated)
  - Extracts contract names and function lines containing `onlyOwner`
  - Writes docs/security/PRIVILEGED_SURFACE_AUTOGEN.md
*/

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

const ROOT = process.cwd();
const CONTRACTS_DIR = path.join(ROOT, 'contracts');
const OUT_PATH = path.join(ROOT, 'docs', 'security', 'PRIVILEGED_SURFACE_AUTOGEN.md');

function walk(dir, out) {
  const entries = fs.readdirSync(dir, { withFileTypes: true });
  for (const entry of entries) {
    const full = path.join(dir, entry.name);
    if (entry.isDirectory()) {
      if (full.includes(`${path.sep}contracts${path.sep}deprecated${path.sep}`)) continue;
      walk(full, out);
    } else if (entry.isFile() && entry.name.endsWith('.sol')) {
      if (full.includes(`${path.sep}contracts${path.sep}deprecated${path.sep}`)) continue;
      out.push(full);
    }
  }
}

function extract(filePath) {
  const content = fs.readFileSync(filePath, 'utf8');
  const lines = content.split(/\r?\n/);

  let contractName = null;
  const results = [];

  for (const line of lines) {
    // Track current contract (best-effort; handles simple `contract X` declarations)
    const contractMatch = line.match(/^\s*contract\s+([A-Za-z0-9_]+)\b/);
    if (contractMatch) contractName = contractMatch[1];

    // Capture function declarations that include onlyOwner on the same line.
    // This repo generally formats modifiers on the same line.
    if (line.includes('function ') && line.includes('onlyOwner')) {
      const cleaned = line
        .replace(/\s*\{\s*$/, '')
        .trim();
      results.push({ contractName: contractName || '(unknown-contract)', signatureLine: cleaned });
    }
  }

  return results;
}

function render(byContract) {
  const parts = [];
  parts.push('# Privileged Surface (Autogenerated)');
  parts.push('');
  parts.push('This file is autogenerated from Solidity sources. Do not hand-edit.');
  parts.push('');
  parts.push('- Generated by: `node tools/generate_privileged_surface.js`');
  parts.push('');
  parts.push('Vaultfire principle: privileged power must be **explicit, reviewable, and minimal**.');
  parts.push('');

  const contracts = Object.keys(byContract).sort((a, b) => a.localeCompare(b));
  if (!contracts.length) {
    parts.push('_No onlyOwner functions detected in non-deprecated contracts._');
    parts.push('');
    return parts.join('\n');
  }

  for (const name of contracts) {
    parts.push(`## ${name}`);
    parts.push('');
    for (const sig of byContract[name]) {
      parts.push('- `' + sig + '`');
    }
    parts.push('');
  }

  parts.push('---');
  parts.push('');
  parts.push('If this list changes, review whether `docs/security/PRIVILEGED_FUNCTIONS.md` and deployment guidance need updates.');
  parts.push('');

  return parts.join('\n');
}

(function main() {
  const files = [];
  walk(CONTRACTS_DIR, files);

  const byContract = {};
  for (const file of files) {
    const hits = extract(file);
    for (const h of hits) {
      byContract[h.contractName] ||= [];
      byContract[h.contractName].push(h.signatureLine);
    }
  }

  // Stable output: sort lines per contract
  for (const key of Object.keys(byContract)) {
    byContract[key] = [...new Set(byContract[key])].sort((a, b) => a.localeCompare(b));
  }

  const output = render(byContract);
  fs.mkdirSync(path.dirname(OUT_PATH), { recursive: true });
  fs.writeFileSync(OUT_PATH, output, 'utf8');
})();
