#!/usr/bin/env node
/**
 * cli:aggregate-component-registry — Entry point.
 *
 * Replaces the legacy "Frontend subagent hand-writes
 * src/extensions/componentRegistry.generated.ts" step. Determinism removes
 * three classes of bugs at once :
 *  1. Phantom imports (Vite fails at launch).
 *  2. Cross-module componentKey collisions (last register() wins, silent).
 *  3. Drift between disk and registry after a module is renamed/deleted.
 *
 * Invocation :
 *   npx --prefer-offline tsx skills/development/frontend/routes/cli/aggregate-component-registry/index.ts \
 *     --project-path "<web-root>"
 *
 * Optional flags :
 *   --modules budgets,crm,catalogue   exhaustive list (orphans → warning)
 *   --out src/extensions/foo.ts       override default output file
 *   --exclude legacyRegistry.ts       skip files (comma-separated basenames)
 *   --dry-run                          report without writing
 */
import { parseArgs } from 'node:util'
import { mkdirSync, writeFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { validate } from './validate.js'
import { generate } from './generate.js'
import {
  generateEnvelope,
  failGenerate,
  printEnvelope,
} from '../../../../../lib/output.js'

const COMMAND = 'aggregate-component-registry'

function main(): void {
  const { values } = parseArgs({
    options: {
      'project-path': { type: 'string' },
      modules: { type: 'string' },
      out: { type: 'string' },
      exclude: { type: 'string' },
      'dry-run': { type: 'boolean', default: false },
    },
    strict: true,
  })

  if (!values['project-path']) {
    printEnvelope(failGenerate(COMMAND, ['--project-path is required']))
    process.exit(1)
  }

  const spec = {
    projectPath: values['project-path'],
    modules: values.modules ? values.modules.split(',').map((s) => s.trim()).filter(Boolean) : undefined,
    outFile: values.out,
    exclude: values.exclude ? values.exclude.split(',').map((s) => s.trim()).filter(Boolean) : [],
  }

  const validation = validate(spec)
  if (!validation.valid) {
    printEnvelope(failGenerate(COMMAND, validation.errors))
    process.exit(1)
  }

  const result = generate(spec)

  // Hard errors — never write a file in this state.
  const errors: string[] = []
  for (const u of result.unresolved) {
    errors.push(
      `Phantom import in ${u.module}Registry.ts: '${u.importPath}' does not resolve on disk. Either restore the missing page or remove the orphan import.`,
    )
  }
  for (const c of result.collisions) {
    errors.push(
      `componentKey collision: '${c.key}' is registered by [${c.modules.join(', ')}]. Last registration wins silently — rename one of them.`,
    )
  }
  if (errors.length > 0) {
    printEnvelope(failGenerate(COMMAND, errors))
    process.exit(1)
  }

  const totalKeys = result.parsed.reduce((acc, p) => acc + p.keys.length, 0)
  const data = {
    modulesAggregated: result.parsed.length,
    registeredKeys: totalKeys,
    modules: result.parsed.map((p) => ({ module: p.module, keys: p.keys.length })),
  }

  if (values['dry-run']) {
    printEnvelope(
      generateEnvelope(COMMAND, {
        data: { ...data, dryRun: true, files: result.files.map((f) => f.path) },
        warnings: result.warnings,
      }),
    )
    process.exit(0)
  }

  const written: string[] = []
  for (const file of result.files) {
    const abs = resolve(spec.projectPath, file.path)
    mkdirSync(dirname(abs), { recursive: true })
    writeFileSync(abs, file.content, 'utf-8')
    written.push(abs)
  }

  printEnvelope(
    generateEnvelope(COMMAND, {
      data,
      filesCreated: written,
      warnings: result.warnings,
      nextSteps: [
        `Import the aggregator from src/main.tsx BEFORE createRoot: import './extensions/componentRegistry.generated';`,
        'Run `npm run build` in the web app to confirm Vite resolves every lazy chunk.',
      ],
    }),
  )
}
main()
