#!/usr/bin/env node
// Sync attractor schema — reads $ATTRACTOR_ROOT/schema.json, generates types/attractor-schema.ts
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';

// ---------------------------------------------------------------------------
// Schema shape (mirrors attractor's schema.json)
// ---------------------------------------------------------------------------

interface RawAttrDef {
  name: string;
  type: string;
  scope: string;
}

interface SchemaJson {
  attributes: {
    node?: Record<string, RawAttrDef>;
    graph?: Record<string, RawAttrDef>;
    edge?: Record<string, RawAttrDef>;
  };
}

// ---------------------------------------------------------------------------
// Code generator
// ---------------------------------------------------------------------------

function generateCode(schema: SchemaJson): string {
  const lines: string[] = [
    '// AUTO-GENERATED by sync-schema — do not edit.',
    '// Source: $ATTRACTOR_ROOT/schema.json — regenerate: npm run sync-schema',
    '',
  ];

  for (const scope of ['node', 'graph', 'edge'] as const) {
    lines.push(`export const ${scope} = {`);
    const attrs: Record<string, RawAttrDef> = schema.attributes[scope] ?? {};
    for (const [key, def] of Object.entries(attrs)) {
      const n = JSON.stringify(def.name);
      const t = JSON.stringify(def.type);
      const s = JSON.stringify(def.scope);
      lines.push(`  ${key}: { name: ${n}, type: ${t}, scope: ${s} },`);
    }
    lines.push(`};`);
    lines.push('');
  }

  lines.push('export const ATTRACTOR_SCHEMA = { node, graph, edge };');
  lines.push('');

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

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

function main(): void {
  const attractorRoot = process.env['ATTRACTOR_ROOT'];

  if (!attractorRoot) {
    process.stderr.write('[sync-schema] WARN: $ATTRACTOR_ROOT not set — skipping schema sync\n');
    process.exit(0);
  }

  const schemaPath = path.join(attractorRoot, 'schema.json');

  let raw: string;
  try {
    raw = fs.readFileSync(schemaPath, 'utf8');
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    process.stderr.write(`[sync-schema] ERROR: could not read ${schemaPath}: ${msg}\n`);
    process.exit(1);
  }

  let parsed: unknown;
  try {
    parsed = JSON.parse(raw);
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    process.stderr.write(`[sync-schema] ERROR: JSON parse error in schema.json: ${msg}\n`);
    process.exit(1);
  }

  if (
    typeof parsed !== 'object' ||
    parsed === null ||
    !('attributes' in parsed) ||
    typeof (parsed as Record<string, unknown>)['attributes'] !== 'object'
  ) {
    process.stderr.write('[sync-schema] ERROR: schema.json missing required "attributes" key\n');
    process.exit(1);
  }

  const schema = parsed as SchemaJson;
  const code = generateCode(schema);

  const __filename = fileURLToPath(import.meta.url);
  const __dirname = path.dirname(__filename);
  const outDir = path.resolve(__dirname, '..', 'types');
  const outPath = path.join(outDir, 'attractor-schema.ts');

  try {
    fs.mkdirSync(outDir, { recursive: true });
    fs.writeFileSync(outPath, code, 'utf8');
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    process.stderr.write(`[sync-schema] ERROR: could not write ${outPath}: ${msg}\n`);
    process.exit(1);
  }

  process.stdout.write(`[sync-schema] generated ${outPath}\n`);
  process.exit(0);
}

if (process.argv[1] && path.basename(process.argv[1]) === 'sync-schema.js') {
  main();
}
