#!/usr/bin/env node
import {
  loadVectorStore,
  saveVectorStore,
  searchVectorStore
} from "./chunk-ZWVIDFGY.js";
import {
  EMBEDDING_DIM,
  embed,
  embedOne
} from "./chunk-KHYD3WXE.js";
import {
  loadIndex
} from "./chunk-OVWE4E46.js";

// src/symbols/semantic.ts
function pathTokens(absFile, root) {
  if (!absFile) return "";
  const norm = absFile.replace(/\\/g, "/");
  let rel = norm;
  if (root) {
    const rootNorm = root.replace(/\\/g, "/").replace(/\/$/, "") + "/";
    if (norm.toLowerCase().startsWith(rootNorm.toLowerCase())) {
      rel = norm.slice(rootNorm.length);
    }
  }
  const noExt = rel.replace(/\.[^./]+$/, "");
  const parts = noExt.split(/[/.\-_]/).filter((t) => {
    if (!t) return false;
    if (t.length < 2) return false;
    if (/^\d+$/.test(t)) return false;
    if (t === "src" || t === "lib" || t === "app" || t === "dist") return false;
    return true;
  });
  const seen = /* @__PURE__ */ new Set();
  const out = [];
  for (const t of parts) {
    const lower = t.toLowerCase();
    if (seen.has(lower)) continue;
    seen.add(lower);
    out.push(t);
    if (out.length >= 6) break;
  }
  return out.join(" ");
}
function buildEmbeddingText(s, root) {
  const parts = [];
  if (root) {
    const tokens = pathTokens(s.location.file, root);
    if (tokens) parts.push(tokens);
  }
  parts.push(s.kind, s.name);
  if (s.container) parts.push(`in ${s.container}`);
  if (s.signature) parts.push(s.signature);
  if (s.doc) parts.push(s.doc);
  return parts.join(" ").slice(0, 512);
}
async function rebuildSemanticIndex(root, opts = {}) {
  const start = Date.now();
  const index = loadIndex(root);
  if (!index) {
    throw new Error(
      `No symbol index for ${root}. Run /index rebuild first so find_symbol has data to embed.`
    );
  }
  const maxSymbols = opts.maxSymbols ?? 2e4;
  const batchSize = opts.batchSize ?? 32;
  const total = Math.min(index.symbols.length, maxSymbols);
  if (total === 0) {
    saveVectorStore(root, new Uint32Array(0), new Float32Array(0));
    return { symbolsEmbedded: 0, durationMs: Date.now() - start };
  }
  const symbolIdx = new Uint32Array(total);
  const vectors = new Float32Array(total * EMBEDDING_DIM);
  let modelFirstLoadMs;
  for (let i = 0; i < total; i += batchSize) {
    const end = Math.min(i + batchSize, total);
    const batch = [];
    for (let j = i; j < end; j++) {
      symbolIdx[j] = j;
      batch.push(buildEmbeddingText(index.symbols[j], index.root));
    }
    const batchStart = Date.now();
    const rows = await embed(batch);
    if (i === 0) modelFirstLoadMs = Date.now() - batchStart;
    for (let r = 0; r < rows.length; r++) {
      vectors.set(rows[r], (i + r) * EMBEDDING_DIM);
    }
    if (opts.onProgress) opts.onProgress(end, total);
  }
  saveVectorStore(root, symbolIdx, vectors);
  return {
    symbolsEmbedded: total,
    durationMs: Date.now() - start,
    modelFirstLoadMs
  };
}
async function semanticSearch(root, query, k = 10) {
  const index = loadIndex(root);
  if (!index) return [];
  const store = loadVectorStore(root);
  if (!store || store.count === 0) return [];
  const queryVec = await embedOne(query);
  const hits = searchVectorStore(store, queryVec, k);
  return hits.map((h) => ({
    ...h,
    symbol: index.symbols[h.symbolIdx]
  })).filter((h) => h.symbol !== void 0);
}
function hasSemanticIndex(root) {
  const s = loadVectorStore(root);
  return s !== null && s.count > 0;
}

export {
  pathTokens,
  buildEmbeddingText,
  rebuildSemanticIndex,
  semanticSearch,
  hasSemanticIndex
};
