import {
  EMBEDDING_DIM
} from "./chunk-JV5N65KN.js";

// src/symbols/vector-store.ts
import fs from "fs";
import path from "path";
import os from "os";
import crypto from "crypto";
var MAGIC = 1094927190;
var VERSION = 1;
var HEADER_BYTES = 16;
function indexDir() {
  return path.join(os.homedir(), ".aicli", "index");
}
function projectHash(root) {
  return crypto.createHash("sha1").update(path.resolve(root).toLowerCase()).digest("hex").slice(0, 16);
}
function vecPath(root) {
  return path.join(indexDir(), `${projectHash(root)}.vec`);
}
function emptyVectorStore(root) {
  return {
    root: path.resolve(root),
    count: 0,
    dim: EMBEDDING_DIM,
    vectors: new Float32Array(0),
    symbolIdx: new Uint32Array(0)
  };
}
function saveVectorStore(root, indices, vectors) {
  if (indices.length * EMBEDDING_DIM !== vectors.length) {
    throw new Error(
      `saveVectorStore: length mismatch \u2014 ${indices.length} indices vs ${vectors.length / EMBEDDING_DIM} vectors`
    );
  }
  const count = indices.length;
  const dir = indexDir();
  fs.mkdirSync(dir, { recursive: true });
  const totalBytes = HEADER_BYTES + count * 4 + count * EMBEDDING_DIM * 4;
  const buf = Buffer.alloc(totalBytes);
  buf.writeUInt32LE(MAGIC, 0);
  buf.writeUInt32LE(VERSION, 4);
  buf.writeUInt32LE(count, 8);
  buf.writeUInt32LE(EMBEDDING_DIM, 12);
  Buffer.from(indices.buffer, indices.byteOffset, indices.byteLength).copy(buf, HEADER_BYTES);
  Buffer.from(vectors.buffer, vectors.byteOffset, vectors.byteLength).copy(buf, HEADER_BYTES + count * 4);
  const target = vecPath(root);
  const tmp = `${target}.tmp`;
  fs.writeFileSync(tmp, buf);
  fs.renameSync(tmp, target);
}
function loadVectorStore(root) {
  const p = vecPath(root);
  if (!fs.existsSync(p)) return null;
  let buf;
  try {
    buf = fs.readFileSync(p);
  } catch {
    return null;
  }
  if (buf.length < HEADER_BYTES) return null;
  const magic = buf.readUInt32LE(0);
  const version = buf.readUInt32LE(4);
  const count = buf.readUInt32LE(8);
  const dim = buf.readUInt32LE(12);
  if (magic !== MAGIC || version !== VERSION || dim !== EMBEDDING_DIM) return null;
  const expected = HEADER_BYTES + count * 4 + count * dim * 4;
  if (buf.length !== expected) return null;
  const symbolIdx = new Uint32Array(
    buf.buffer.slice(buf.byteOffset + HEADER_BYTES, buf.byteOffset + HEADER_BYTES + count * 4)
  );
  const vectors = new Float32Array(
    buf.buffer.slice(
      buf.byteOffset + HEADER_BYTES + count * 4,
      buf.byteOffset + HEADER_BYTES + count * 4 + count * dim * 4
    )
  );
  return { root: path.resolve(root), count, dim, vectors, symbolIdx };
}
function clearVectorStore(root) {
  const p = vecPath(root);
  try {
    if (fs.existsSync(p)) fs.unlinkSync(p);
  } catch {
  }
}
function searchVectorStore(store, queryVec, k) {
  if (store.count === 0) return [];
  if (queryVec.length !== store.dim) {
    throw new Error(`searchVectorStore: dim mismatch (query=${queryVec.length}, store=${store.dim})`);
  }
  const { count, dim, vectors, symbolIdx } = store;
  const top = [];
  let minSlot = -1;
  const recomputeMin = () => {
    minSlot = 0;
    for (let i = 1; i < top.length; i++) {
      if (top[i].score < top[minSlot].score) minSlot = i;
    }
  };
  for (let row = 0; row < count; row++) {
    const base = row * dim;
    let score = 0;
    for (let d = 0; d < dim; d++) {
      score += vectors[base + d] * queryVec[d];
    }
    if (top.length < k) {
      top.push({ row, symbolIdx: symbolIdx[row], score });
      if (top.length === k) recomputeMin();
    } else if (score > top[minSlot].score) {
      top[minSlot] = { row, symbolIdx: symbolIdx[row], score };
      recomputeMin();
    }
  }
  return top.sort((a, b) => b.score - a.score);
}

export {
  emptyVectorStore,
  saveVectorStore,
  loadVectorStore,
  clearVectorStore,
  searchVectorStore
};
