/**
 * db/oracle-docs.js — retrieval over the oracle_doc_chunks RAG store.
 *
 * Owns: cosine-similarity search of Oracle documentation chunks embedded by
 *       scripts/ingest-oracle-docs.js (text-embedding-3-small, 1536 dims).
 * Does NOT own: embedding generation (caller supplies the query vector),
 *               ingestion, TuneBot prompt assembly.
 */

'use strict';

const pool = require('./index');

/**
 * Return the top-N most similar doc chunks to a query embedding.
 * Uses Oracle 26ai native cosine distance (VECTOR_DISTANCE(..., COSINE)) against
 * the ORACLE_DOC_CHUNKS_EMBEDDING_IDX NEIGHBOR PARTITIONS vector index — the
 * pgvector `<=>` / ivfflat equivalent.
 *
 * @param {number[]} embedding  — 1536-dim query vector (same model as ingestion)
 * @param {Object}   [opts]
 * @param {number}   [opts.limit=5]      — max chunks to return
 * @param {number}   [opts.minSimilarity=0.3] — drop weak matches (0..1; cosine)
 * @returns {Promise<Array<{doc_name, chunk_index, content, similarity}>>}
 */
async function searchDocChunks(embedding, { limit = 5, minSimilarity = 0.3 } = {}) {
  if (!Array.isArray(embedding) || embedding.length === 0) return [];
  // pgvector took the query vector as a '[...]' text literal cast ::vector; Oracle
  // binds it as a native FLOAT32 VECTOR (a plain array would bind FLOAT64 and
  // ORA-51812 — see pool.vector). :p1 is reused in the SELECT and ORDER BY; a
  // named bind is used once for both. FETCH APPROX FIRST engages the ANN index
  // (the ivfflat equivalent); similarity = 1 - cosine distance.
  const vec = pool.vector(embedding);
  const { rows } = await pool.query(
    `SELECT doc_name,
            chunk_index,
            content,
            1 - VECTOR_DISTANCE(embedding, :p1, COSINE) AS similarity
       FROM oracle_doc_chunks
      ORDER BY VECTOR_DISTANCE(embedding, :p1, COSINE)
      FETCH APPROX FIRST :p2 ROWS ONLY`,
    { p1: vec, p2: limit }
  );
  return rows.filter(r => Number(r.similarity) >= minSimilarity);
}

module.exports = { searchDocChunks };
