// tools/registry-load.mjs
// Pure module — загрузка и индексация реестра узлов.
// Никаких сетевых вызовов, никакого фс-исключения кроме чтения.

import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import yaml from 'js-yaml';
import Ajv from 'ajv';
import addFormats from 'ajv-formats';

const __dirname = dirname(fileURLToPath(import.meta.url));
const DEFAULT_REGISTRY_PATH = join(__dirname, '..', 'docs', 'registry', 'nodes.yaml');
const DEFAULT_SCHEMA_PATH = join(__dirname, '..', 'docs', 'registry', 'schema.json');

let _cached = null;

export function loadRegistry({ registryPath = DEFAULT_REGISTRY_PATH, schemaPath = DEFAULT_SCHEMA_PATH, useCache = true } = {}) {
  if (useCache && _cached) return _cached;

  const schema = JSON.parse(readFileSync(schemaPath, 'utf-8'));
  const data = yaml.load(readFileSync(registryPath, 'utf-8'));

  const ajv = new Ajv({ allErrors: true });
  addFormats(ajv);
  const validate = ajv.compile(schema);
  if (!validate(data)) {
    throw new Error(`Registry schema violation:\n${JSON.stringify(validate.errors, null, 2)}`);
  }

  const indexById = new Map();
  for (const node of data.nodes) indexById.set(node.id, node);

  const indexByTrigger = new Map();
  for (const node of data.nodes) {
    if (node.status !== 'active') continue;
    for (const t of node.triggers || []) {
      const key = t.classification ? `cls:${t.classification}` :
                  t.keyword ? `kw:${t.keyword.toLowerCase()}` :
                  t.file_pattern ? `fp:${t.file_pattern}` : null;
      if (!key) continue;
      if (!indexByTrigger.has(key)) indexByTrigger.set(key, []);
      indexByTrigger.get(key).push({ node, weight: t.weight ?? 1.0 });
    }
  }

  const result = {
    nodes: data.nodes,
    chains: data.chains,
    version: data.version,
    indexById,
    indexByTrigger,
  };
  if (useCache) _cached = result;
  return result;
}

export function clearCache() { _cached = null; }

export function findByClassification(registry, classification) {
  return (registry.indexByTrigger.get(`cls:${classification}`) || [])
    .sort((a, b) => b.weight - a.weight);
}

export function findByKeyword(registry, keyword) {
  return (registry.indexByTrigger.get(`kw:${keyword.toLowerCase()}`) || [])
    .sort((a, b) => b.weight - a.weight);
}

export function findActiveNodes(registry) {
  return registry.nodes.filter(n => n.status === 'active');
}

export function findChainsByNode(registry, nodeIdOrSlug) {
  const chains = [];
  for (const [chainId, chain] of Object.entries(registry.chains)) {
    if (chain.sequence.some(s => s === nodeIdOrSlug)) {
      chains.push({ chainId, ...chain });
    }
  }
  return chains;
}
