#!/usr/bin/env node

// Generate tool inventory from tools-defs.js (single source of truth)
// Outputs: docs/TOOLS.md + docs/tool-count.json

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

// ── Mock all runtime dependencies so we can load tools-defs.js statically ──

// Mock platform to enable all platform-conditional tools
jest_mock('../web/src/platform', { IS_MAC: true, IS_WIN: true, IS_LINUX: true });

// Mock context to enable all connection-gated tools
jest_mock('../web/src/context', {
  getActiveConnections: () => ({
    github: true, google: true, jira: true, confluence: true,
    smartsheet: true, microsoft: true, slack: true, wolfram: true,
    telegram: true, linear: true, zoom: true, figma: true,
    asana: true, dynamics365: true,
  }),
  isComfyUIInstalled: () => true,
});

// Mock computer use + browser as available
jest_mock('../web/src/tools/computer', { isAvailable: () => true, setTargetApp() {}, maximizeTargetWindow() {}, restoreFocus() {} });
jest_mock('../web/src/tools/browser', { isAvailable: () => true });
jest_mock('../web/src/tools/voice', { hasWhisper: true, hasSay: true });

// Mock MCP (no dynamic MCP tools in inventory)
jest_mock('../web/src/mcp', { getAllTools: () => [] });

// Mock custom tools (no dynamic custom tools in inventory)
jest_mock('../web/src/custom-tools', { buildCustomToolDefs: () => [] });

// Mock tool-tiers (allow all tools through)
jest_mock('../web/src/tool-tiers', { isToolAllowed: () => true });

// Mock constants
jest_mock('../web/src/constants', {
  PRE_DIR: '/tmp/pre-gen-docs',
  MODEL: 'pre-gemma4',
  MODEL_CTX: 131072,
  OLLAMA_PORT: 11434,
  MAX_TOOL_TURNS: 35,
  SESSIONS_DIR: '/tmp/pre-gen-docs/sessions',
  MEMORY_DIR: '/tmp/pre-gen-docs/memory',
  ARTIFACTS_DIR: '/tmp/pre-gen-docs/artifacts',
  CONNECTIONS_FILE: '/tmp/pre-gen-docs/connections.json',
  COMFYUI_FILE: '/tmp/pre-gen-docs/comfyui.json',
  CRON_FILE: '/tmp/pre-gen-docs/cron.json',
});

function jest_mock(modulePath, impl) {
  const resolved = require.resolve(path.resolve(__dirname, modulePath));
  require.cache[resolved] = {
    id: resolved,
    filename: resolved,
    loaded: true,
    exports: impl,
  };
}

// ── Load tool definitions ──

const { buildToolDefs } = require(path.resolve(__dirname, '../web/src/tools-defs'));
const tools = buildToolDefs(); // no domain filtering = all tools

// ── Domain taxonomy (from tool-tiers.js) ──

const CORE_TOOLS = new Set([
  'bash', 'read_file', 'list_dir', 'glob', 'grep',
  'file_write', 'file_edit', 'web_fetch', 'web_search',
  'memory_save', 'memory_search', 'memory_list', 'memory_delete',
  'system_info', 'spotlight', 'artifact', 'document',
  'screenshot', 'request_tools', 'session_search',
]);

const DOMAINS = {
  'Core': Array.from(CORE_TOOLS),
  'DevOps & System': ['process_list', 'process_kill', 'monitor', 'service_status', 'net_info', 'net_connections', 'disk_usage', 'hardware_info'],
  'Desktop Automation': ['computer', 'window_list', 'window_focus', 'display_info', 'clipboard_read', 'clipboard_write', 'open_app', 'notify'],
  'Personal Information': ['apple_mail', 'apple_calendar', 'apple_contacts', 'apple_reminders', 'apple_notes'],
  'Scripting': ['applescript', 'powershell_script'],
  'Media & Browser': ['image_generate', 'voice', 'pdf_export', 'browser'],
  'Automation & Intelligence': ['cron', 'spawn_agent', 'spawn_multi', 'list_agents', 'background_agent', 'trigger', 'custom_tool', 'experience_search', 'experience_list', 'memory_health', 'workflow', 'rag', 'training_export', 'finetune', 'calibration', 'knowledge_graph'],
  'Cloud Integrations': ['github', 'gmail', 'gdrive', 'gdocs', 'jira', 'confluence', 'smartsheet', 'slack', 'sharepoint', 'linear', 'zoom', 'figma', 'asana', 'dynamics365', 'telegram', 'wolfram'],
};

// Build a lookup: tool name → domain
const toolDomain = {};
for (const [domain, names] of Object.entries(DOMAINS)) {
  for (const n of names) toolDomain[n] = domain;
}

// ── Build tool map ──

const toolMap = new Map();
for (const t of tools) {
  const name = t.function.name;
  const desc = t.function.description;
  const params = t.function.parameters?.properties || {};
  const required = t.function.parameters?.required || [];
  toolMap.set(name, { name, description: desc, params, required, domain: toolDomain[name] || 'Other' });
}

// ── Generate TOOLS.md ──

const lines = [];
lines.push('# PRE Tool Inventory');
lines.push('');
lines.push(`> Auto-generated from \`web/src/tools-defs.js\` — do not edit manually.`);
lines.push(`> Regenerate: \`npm run gen:docs\` (from \`web/\`) or \`node scripts/gen-tool-docs.js\``);
lines.push('');
lines.push(`**${toolMap.size} tools** across ${Object.keys(DOMAINS).length} domains.`);
lines.push('');

// Table of contents
lines.push('## Domains');
lines.push('');
for (const domain of Object.keys(DOMAINS)) {
  const count = DOMAINS[domain].filter(n => toolMap.has(n)).length;
  const anchor = domain.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/-+$/, '');
  lines.push(`- [${domain}](#${anchor}) (${count})`);
}
// Check for tools not in any domain
const otherTools = [...toolMap.values()].filter(t => t.domain === 'Other');
if (otherTools.length > 0) {
  lines.push(`- [Other](#other) (${otherTools.length})`);
}
lines.push('');

// Domain sections
for (const [domain, names] of Object.entries(DOMAINS)) {
  const domainTools = names.filter(n => toolMap.has(n)).map(n => toolMap.get(n));
  if (domainTools.length === 0) continue;

  lines.push(`## ${domain}`);
  lines.push('');
  lines.push('| Tool | Description | Parameters |');
  lines.push('|------|-------------|------------|');

  for (const t of domainTools) {
    const paramNames = Object.keys(t.params);
    const reqSet = new Set(t.required);
    const paramStr = paramNames.length === 0
      ? '(none)'
      : paramNames.map(p => reqSet.has(p) ? `**${p}**` : p).join(', ');
    const desc = t.description.split('.')[0].replace(/\|/g, '/'); // first sentence, escape pipes
    lines.push(`| \`${t.name}\` | ${desc} | ${paramStr} |`);
  }
  lines.push('');
}

// Other (uncategorized) tools
if (otherTools.length > 0) {
  lines.push('## Other');
  lines.push('');
  lines.push('| Tool | Description | Parameters |');
  lines.push('|------|-------------|------------|');
  for (const t of otherTools) {
    const paramNames = Object.keys(t.params);
    const reqSet = new Set(t.required);
    const paramStr = paramNames.length === 0
      ? '(none)'
      : paramNames.map(p => reqSet.has(p) ? `**${p}**` : p).join(', ');
    const desc = t.description.split('.')[0].replace(/\|/g, '/');
    lines.push(`| \`${t.name}\` | ${desc} | ${paramStr} |`);
  }
  lines.push('');
}

// Legend
lines.push('---');
lines.push('');
lines.push('**Bold** parameters are required. Core tools load by default; other domains activate via `request_tools` or auto-detection.');
lines.push('');
lines.push('Cloud integrations require credentials in `~/.pre/connections.json`. Desktop automation requires `cliclick` (macOS), `xdotool` (Linux), or native P/Invoke (Windows). Image generation requires ComfyUI.');

// ── Generate tool-count.json ──

const byDomain = {};
for (const [domain, names] of Object.entries(DOMAINS)) {
  byDomain[domain] = names.filter(n => toolMap.has(n)).length;
}
if (otherTools.length > 0) byDomain['Other'] = otherTools.length;

const countData = {
  total: toolMap.size,
  core: CORE_TOOLS.size,
  byDomain,
};

// ── Write output ──

const docsDir = path.resolve(__dirname, '../docs');
if (!fs.existsSync(docsDir)) fs.mkdirSync(docsDir, { recursive: true });

fs.writeFileSync(path.join(docsDir, 'TOOLS.md'), lines.join('\n'));
fs.writeFileSync(path.join(docsDir, 'tool-count.json'), JSON.stringify(countData, null, 2) + '\n');

console.log(`Generated docs/TOOLS.md (${toolMap.size} tools) and docs/tool-count.json`);
