import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { WEBSOCKET_COMMANDS } from '../src/contracts/websocket-commands.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(__dirname, '../..');
const outputPath = path.join(repoRoot, 'docs', 'WEBSOCKET_CONTRACT.md');

function formatPayload(variant: (typeof WEBSOCKET_COMMANDS)[string]['payloads'][number]): string {
  switch (variant.kind) {
    case 'empty':
      return 'empty';
    case 'string':
      return `string (${variant.description})`;
    case 'number':
      return variant.description ? `number (${variant.description})` : 'number';
    case 'object': {
      const fields = Object.entries(variant.fields)
        .map(([key, spec]) => `${key}: ${spec.type}${spec.optional ? '?' : ''}`)
        .join(', ');
      return `{ ${fields} }`;
    }
    default:
      return 'unknown';
  }
}

function generate(): string {
  const lines: string[] = [
    '# WebSocket Contract',
    '',
    '> Auto-generated from `server/src/contracts/websocket-commands.ts`.',
    '> Do not edit manually — run `npm run contract:docs` in `server/`.',
    '',
    `Generated: ${new Date().toISOString()}`,
    '',
    '## Client → Server Commands',
    '',
    '| Command | Envelope | Payload variants | Responses | Clients | Notes |',
    '|---------|----------|------------------|-----------|---------|-------|',
  ];

  const sorted = Object.entries(WEBSOCKET_COMMANDS).sort(([a], [b]) => a.localeCompare(b));

  for (const [name, contract] of sorted) {
    if (contract.direction !== 'client-to-server') continue;

    const payloads = contract.payloads.map(formatPayload).join('<br>');
    const responses =
      contract.responses?.map((r) => r.type).join(', ') ?? '—';
    const clients = contract.clients.join(', ');
    const notes = [
      contract.flags?.join(', '),
      contract.semanticNote,
    ]
      .filter(Boolean)
      .join('; ') || '—';

    lines.push(
      `| \`${name}\` | ${contract.envelope} | ${payloads} | ${responses} | ${clients} | ${notes} |`
    );
  }

  lines.push('', '## Envelope Types', '');
  lines.push('- **message-field**: `{ type, message: payload }` — canonical');
  lines.push('- **command-alias**: `{ type: "command", message: "start"|"stop"|"restart" }`');
  lines.push('- **top-level**: extra fields at envelope root (legacy Android)');
  lines.push('- **empty**: `{ type }` only, no message body');
  lines.push('- **init-only**: `{ type: "init", userID }` handled before registry dispatch');
  lines.push('');

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

const markdown = generate();
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, markdown, 'utf8');
console.log(`Wrote ${outputPath}`);
