/**
 * Codegen: packages/myco/src/hooks/hook-config.generated.ts
 *
 * Every Myco hook runs in a short-lived Node process; cursor in particular
 * fires hooks on nearly every keystroke. Parsing the 8 symbiont YAML
 * manifests + running Zod validation at hook startup was the single largest
 * per-hook cost on feat/steering-prompt-capture. The manifests are static
 * at runtime — they ship inside the dist bundle and never change outside
 * of development — so bake the hook-relevant subset into TypeScript at
 * build time.
 *
 * Only the fields hooks actually read make it into the generated const:
 *   - registration.hookResponse (format + fieldNames)
 *   - capture.prompts (shapes, resetBoundaries, interruptMarker)
 *   - capture.rules
 *
 * Skills, MCP targets, hook-target paths, installer fields, etc. live
 * outside the hook hot path and stay loaded through loadManifests() for
 * the installer / daemon / UI.
 *
 * Run manually via: npx tsx packages/myco/scripts/gen-hook-config.ts
 * Wired into npm: `npm run codegen` runs automatically before `npm run build`.
 */
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import YAML from 'yaml';
import { SymbiontManifestSchema } from '../src/symbionts/manifest-schema.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PACKAGE_ROOT = path.resolve(__dirname, '..');
const MANIFESTS_DIR = path.resolve(PACKAGE_ROOT, 'src/symbionts/manifests');
const OUTPUT_PATH = path.resolve(PACKAGE_ROOT, 'src/hooks/hook-config.generated.ts');
const FULL_MANIFESTS_OUTPUT_PATH = path.resolve(PACKAGE_ROOT, 'src/symbionts/manifests.generated.ts');

interface HookConfigEntry {
  hookResponse?: unknown;
  capturePrompts?: unknown;
  captureRules?: unknown;
}

function main(): void {
  if (!fs.existsSync(MANIFESTS_DIR)) {
    throw new Error(`manifests directory missing: ${MANIFESTS_DIR}`);
  }
  const files = fs.readdirSync(MANIFESTS_DIR)
    .filter((f) => f.endsWith('.yaml'))
    .sort();
  if (files.length === 0) {
    throw new Error(`no YAML manifests found in ${MANIFESTS_DIR}`);
  }

  const entries: Record<string, HookConfigEntry> = {};
  for (const file of files) {
    const raw = YAML.parse(fs.readFileSync(path.join(MANIFESTS_DIR, file), 'utf-8'));
    const manifest = SymbiontManifestSchema.parse(raw);
    const entry: HookConfigEntry = {};
    const hookResponse = manifest.registration?.hookResponse;
    if (hookResponse) entry.hookResponse = hookResponse;
    const capturePrompts = manifest.capture?.prompts;
    if (capturePrompts) entry.capturePrompts = capturePrompts;
    const captureRules = manifest.capture?.rules;
    if (captureRules && captureRules.length > 0) entry.captureRules = captureRules;
    entries[manifest.name] = entry;
  }

  const body = JSON.stringify(entries, null, 2);
  const output = `// AUTO-GENERATED by scripts/gen-hook-config.ts — DO NOT EDIT.
// Run \`npm run codegen\` (or \`npx tsx packages/myco/scripts/gen-hook-config.ts\`) to regenerate.
//
// This file bakes the hook-relevant subset of every symbiont manifest into
// a typed const so hooks don't pay for YAML I/O + Zod parsing on every
// short-lived hook process. Keep it checked into git so tests don't need
// a build step.

import type {
  CapturePrompts,
  CaptureRule,
  SymbiontRegistration,
} from '../symbionts/manifest-schema.js';

export interface HookConfigEntry {
  hookResponse?: NonNullable<SymbiontRegistration['hookResponse']>;
  capturePrompts?: CapturePrompts;
  captureRules?: CaptureRule[];
}

export const HOOK_CONFIG: Readonly<Record<string, HookConfigEntry>> = ${body} as const;
`;

  fs.writeFileSync(OUTPUT_PATH, output);
  process.stdout.write(`[gen-hook-config] wrote ${path.relative(PACKAGE_ROOT, OUTPUT_PATH)} (${Object.keys(entries).length} symbionts)\n`);

  // Also emit the full parsed manifests so `loadManifests()` can fall back to
  // the bundled data when the filesystem layout is absent (compiled Bun binary:
  // manifest YAML files are inside the /$bunfs/ virtual FS and fs.readdirSync
  // can't enumerate them).
  const fullManifests: unknown[] = [];
  for (const file of files) {
    const raw = YAML.parse(fs.readFileSync(path.join(MANIFESTS_DIR, file), 'utf-8'));
    const manifest = SymbiontManifestSchema.parse(raw);
    fullManifests.push(manifest);
  }
  const fullOutput = `// AUTO-GENERATED by scripts/gen-hook-config.ts — DO NOT EDIT.
// Run \`npm run codegen\` to regenerate.
//
// Full parsed symbiont manifests bundled for the compiled binary path.
// loadManifests() in symbionts/detect.ts prefers the filesystem candidates
// (source/dist layouts) when they're populated and falls back to this array
// for the compiled-Bun case where manifest YAMLs aren't enumerable on disk.

import type { SymbiontManifest } from './manifest-schema.js';

export const BUNDLED_MANIFESTS: readonly SymbiontManifest[] = ${JSON.stringify(fullManifests, null, 2)} as const;
`;
  fs.writeFileSync(FULL_MANIFESTS_OUTPUT_PATH, fullOutput);
  process.stdout.write(`[gen-hook-config] wrote ${path.relative(PACKAGE_ROOT, FULL_MANIFESTS_OUTPUT_PATH)} (${fullManifests.length} manifests)\n`);
}

main();
