// Embedding module — ONNX-based local embeddings.
// Falls back gracefully when the model file is not available.

let model: any = null;
let ortModule: any = null;

export function isEmbeddingAvailable(): boolean {
  return model !== null;
}

// eslint-disable-next-line @typescript-eslint/no-require-imports
const dynamicRequire = typeof require !== 'undefined' ? require : null;

export async function initEmbeddings(modelPath?: string): Promise<boolean> {
  try {
    if (dynamicRequire) {
      try { ortModule = dynamicRequire('onnxruntime-node'); } catch { ortModule = null; }
    }
    if (!ortModule) {
      try { ortModule = await import('onnxruntime-node' as any); } catch { ortModule = null; }
    }
    if (!ortModule) return false;
    const path = modelPath ?? process.env['EMBEDDING_MODEL_PATH'] ?? '';
    if (!path) return false;
    model = await ortModule.InferenceSession.create(path);
    return true;
  } catch {
    model = null;
    return false;
  }
}

export async function embed(texts: string[]): Promise<number[][] | null> {
  if (!model) return null;
  try {
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
    const ort: { Tensor: new (...args: unknown[]) => unknown } | null = ortModule || null;
    if (!ort) return null;
    const input = new ort.Tensor('string', texts, [texts.length]);
    const feeds: Record<string, any> = {};
    feeds[model.inputNames[0]] = input;
    const results = await model.run(feeds);
    const output = results[model.outputNames[0]];
    if (!output || !output.data) return null;
    const dim = output.dims?.[1] ?? 384;
    const data = output.data as Float32Array;
    const vectors: number[][] = [];
    for (let i = 0; i < texts.length; i++) {
      vectors.push(Array.from(data.slice(i * dim, (i + 1) * dim)));
    }
    return vectors;
  } catch {
    return null;
  }
}
