#!/usr/bin/env node
import { readFileSync, writeFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const scriptDir = dirname(fileURLToPath(import.meta.url));
const docsRoot = resolve(scriptDir, '..');
const repoRoot = resolve(docsRoot, '..');
const mainRs = resolve(repoRoot, 'src/main.rs');
const outputPath = resolve(docsRoot, 'content/docs/reference/command-map.md');
const check = process.argv.includes('--check');

const source = readFileSync(mainRs, 'utf8');

function toKebab(name) {
  return name
    .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
    .replace(/_/g, '-')
    .toLowerCase();
}

function enumBody(enumName) {
  const marker = `enum ${enumName}`;
  const start = source.indexOf(marker);
  if (start === -1) {
    throw new Error(`enum ${enumName} não encontrado em src/main.rs`);
  }

  const open = source.indexOf('{', start);
  let depth = 0;
  for (let index = open; index < source.length; index += 1) {
    const char = source[index];
    if (char === '{') depth += 1;
    if (char === '}') depth -= 1;
    if (depth === 0) return source.slice(open + 1, index);
  }

  throw new Error(`enum ${enumName} sem fechamento`);
}

function enumVariants(enumName) {
  return [...enumBody(enumName).matchAll(/^\s*([A-Z][A-Za-z0-9_]*)\b/gm)]
    .map((match) => match[1])
    .filter((name) => !['COMANDOS', 'EXEMPLOS', 'CANAIS', 'CONFIGURA'].includes(name));
}

const topLevel = new Set(enumVariants('Command').map(toKebab));

function requireTop(command) {
  if (!topLevel.has(command)) {
    throw new Error(`comando esperado ausente no enum Command: ${command}`);
  }
  return command;
}

function subcommands(enumName, prefix, only) {
  const variants = new Set(enumVariants(enumName).map(toKebab));
  for (const item of only) {
    if (!variants.has(item)) {
      throw new Error(`subcomando esperado ausente em ${enumName}: ${item}`);
    }
  }
  return only.map((item) => `${prefix} ${item}`);
}

const groups = [
  {
    title: 'Setup e saúde',
    commands: ['init', 'install', 'update', 'doctor', 'health', 'ci'].map(requireTop),
  },
  {
    title: 'Clients',
    commands: subcommands('ClientsCommand', 'clients', ['list', 'doctor', 'sync']),
  },
  {
    title: 'Capabilities',
    commands: subcommands('CapabilitiesCommand', 'capabilities', [
      'list',
      'doctor',
      'sync',
      'recommend',
    ]),
  },
  {
    title: 'Skills',
    commands: subcommands('SkillsCommand', 'skills', [
      'list',
      'doctor',
      'sync',
      'recommend',
      'validate',
    ]),
  },
  {
    title: 'Workflow',
    commands: subcommands('WorkflowCommand', 'workflow', ['list', 'validate', 'run', 'status']),
  },
  {
    title: 'MCP e ACP',
    commands: [
      ...subcommands('McpCommand', 'mcp', ['serve', 'config', 'doctor']),
      ...subcommands('AcpCommand', 'acp', ['serve', 'doctor', 'config']),
    ],
  },
  {
    title: 'Trace e contexto',
    commands: [
      ...subcommands('TraceCommand', 'trace', ['list', 'show', 'summary', 'doctor']),
      ...subcommands('ContextCommand', 'context', ['build', 'recommend', 'materialize']),
      'context build --metadata-only',
    ],
  },
  {
    title: 'Manutenção',
    commands: subcommands('MaintenanceCommand', 'maintenance', ['report']),
  },
  {
    title: 'Providers',
    commands: subcommands('ProvidersCommand', 'providers', ['list', 'doctor']),
  },
  {
    title: 'Stages',
    commands: [
      'discover',
      'risk',
      'idea',
      'prd',
      'techspec',
      'tasks',
      'refinement',
      'execution',
      'adr',
      'review',
      'memory',
      'resolve-input',
      'orchestration',
    ].map(requireTop),
  },
  {
    title: 'Artifact store',
    commands: [
      ...subcommands('ArtifactCommand', 'artifact', ['init', 'save', 'status', 'link']),
      requireTop('validate-artifact'),
    ],
  },
  {
    title: 'Avaliação e qualidade',
    commands: [
      ...subcommands('EvalCommand', 'eval', ['stage', 'orchestration']),
      ...subcommands('QualityCommand', 'quality', ['report']),
    ],
  },
  {
    title: 'Intelligence e otimização',
    commands: [
      ...subcommands('IntelligenceCommand', 'intelligence', ['learn', 'status', 'health', 'repair']),
      ...subcommands('OptimizeCommand', 'optimize', ['status', 'compress']),
    ],
  },
  {
    title: 'Diagramas',
    commands: subcommands('DiagramCommand', 'diagram', ['attach', 'doctor']),
  },
  {
    title: 'Automação',
    commands: [
      ...subcommands('DemandCommand', 'demand', ['enqueue', 'list', 'status', 'approve', 'reject']),
      ...subcommands('AutoCommand', 'auto', ['tick', 'run', 'status']),
      requireTop('hook'),
      requireTop('worktree'),
      requireTop('bot'),
      requireTop('tui'),
    ],
  },
];

const rows = groups
  .map(
    (group) =>
      `| ${group.title} | ${group.commands.map((command) => `\`${command}\``).join(', ')} |`,
  )
  .join('\n');

const generated = `---
title: Mapa de comandos
description: Referência dos comandos principais, sincronizada com o contrato Clap do CLI.
context: Consulta rápida para operadores e agents.
---

# Mapa de comandos

Esta página é gerada por \`npm run docs:generate\` a partir dos enums Clap em \`src/main.rs\`. Edite a fonte do CLI ou o script de geração quando um comando mudar.

| Grupo | Comandos |
|---|---|
${rows}

## Comandos frequentes

\`\`\`bash
sdd doctor
sdd clients doctor --strict
sdd skills doctor --strict
sdd workflow validate standard-sdd --json
sdd init "minha-orquestracao"
sdd orchestration "minha ideia"
sdd quality report --name "minha-orquestracao" --json
\`\`\`

## Como aprofundar

Use \`sdd <comando> --help\` para opções completas. Para subcomandos, use \`sdd <grupo> <subcomando> --help\`.

## Manutenção

\`\`\`bash
cd docs-site
npm run docs:generate -- --check
\`\`\`

Se o check falhar, rode \`npm run docs:generate -- --write\`, revise o diff e confirme que a página ainda ensina o fluxo correto.
`;

if (check) {
  const current = readFileSync(outputPath, 'utf8');
  if (current !== generated) {
    console.error('content/docs/reference/command-map.md está desatualizado.');
    console.error('Rode: npm run docs:generate -- --write');
    process.exit(1);
  }
  process.exit(0);
}

if (!process.argv.includes('--write')) {
  process.stdout.write(generated);
  process.exit(0);
}

writeFileSync(outputPath, generated);
