"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var vec_index_exports = {};
__export(vec_index_exports, {
  VecIndex: () => VecIndex
});
module.exports = __toCommonJS(vec_index_exports);
var path = __toESM(require("path"));
var import_errors = require("../errors");
const DEFAULT_DIM = 768;
class VecIndex {
  constructor(kirographDir, dim = DEFAULT_DIM) {
    this.kirographDir = kirographDir;
    this.db = null;
    this._available = false;
    this.dim = dim;
  }
  isAvailable() {
    return this._available;
  }
  /**
   * Load better-sqlite3 + sqlite-vec and create the vec schema.
   * No-op and silent when optional deps are missing.
   */
  async initialize() {
    if (this._available) return;
    const dbPath = path.join(this.kirographDir, "vec.db");
    let BetterSQLite;
    let sqliteVec;
    try {
      BetterSQLite = require("better-sqlite3");
    } catch {
      (0, import_errors.logDebug)("VecIndex: better-sqlite3 not installed \u2014 sqlite-vec unavailable");
      return;
    }
    try {
      sqliteVec = require("sqlite-vec");
    } catch {
      (0, import_errors.logDebug)("VecIndex: sqlite-vec not installed \u2014 falling back to in-process cosine search");
      return;
    }
    try {
      this.db = new BetterSQLite(dbPath);
      sqliteVec.load(this.db);
      const mapInfo = this.db.pragma("table_info(vec_nodes_map)");
      const hasVecRowid = mapInfo.some((col) => col.name === "vec_rowid");
      if (mapInfo.length > 0 && !hasVecRowid) {
        (0, import_errors.logDebug)("VecIndex: stale schema detected, rebuilding vec.db");
        this.db.exec(`
          DROP TABLE IF EXISTS vec_nodes_map;
          DROP TABLE IF EXISTS vec_nodes;
        `);
      }
      this.db.exec(`
        CREATE VIRTUAL TABLE IF NOT EXISTS vec_nodes
          USING vec0(embedding float[${this.dim}]);
        CREATE TABLE IF NOT EXISTS vec_nodes_map (
          node_id TEXT PRIMARY KEY NOT NULL,
          vec_rowid INTEGER NOT NULL
        );
      `);
      this._available = true;
      (0, import_errors.logDebug)("VecIndex: initialized", { dbPath, dim: this.dim });
    } catch (err) {
      (0, import_errors.logError)("VecIndex: initialization failed", { error: String(err) });
      this._available = false;
      if (this.db) {
        try {
          this.db.close();
        } catch {
        }
        this.db = null;
      }
    }
  }
  /**
   * Insert or update the embedding for a node.
   * We let vec_nodes auto-assign its rowid (avoiding the SQLITE_INTEGER type
   * mismatch that occurs when passing explicit JS number rowids to vec0).
   * The auto-assigned rowid is stored in vec_nodes_map for later lookup.
   * vec0 tables don't support UPDATE, so updates are a DELETE + INSERT pair.
   */
  upsert(nodeId, embedding) {
    if (!this._available || !this.db) return;
    try {
      const existing = this.db.prepare("SELECT vec_rowid FROM vec_nodes_map WHERE node_id = ?").get(nodeId);
      if (existing) {
        this.db.prepare("DELETE FROM vec_nodes WHERE rowid = ?").run(existing.vec_rowid);
        const result = this.db.prepare("INSERT INTO vec_nodes(embedding) VALUES (?)").run(embedding);
        this.db.prepare("UPDATE vec_nodes_map SET vec_rowid = ? WHERE node_id = ?").run(result.lastInsertRowid, nodeId);
      } else {
        const result = this.db.prepare("INSERT INTO vec_nodes(embedding) VALUES (?)").run(embedding);
        this.db.prepare("INSERT INTO vec_nodes_map(node_id, vec_rowid) VALUES (?, ?)").run(nodeId, result.lastInsertRowid);
      }
    } catch (err) {
      (0, import_errors.logWarn)("VecIndex: upsert failed", { nodeId, error: String(err) });
    }
  }
  /**
   * Remove a node's embedding from the index.
   * Called explicitly when a node is deleted; stale entries are also filtered
   * harmlessly in search() since GraphDatabase.getNode() will return null.
   */
  delete(nodeId) {
    if (!this._available || !this.db) return;
    try {
      const existing = this.db.prepare("SELECT vec_rowid FROM vec_nodes_map WHERE node_id = ?").get(nodeId);
      if (existing) {
        this.db.prepare("DELETE FROM vec_nodes WHERE rowid = ?").run(existing.vec_rowid);
        this.db.prepare("DELETE FROM vec_nodes_map WHERE node_id = ?").run(nodeId);
      }
    } catch (err) {
      (0, import_errors.logWarn)("VecIndex: delete failed", { nodeId, error: String(err) });
    }
  }
  /**
   * ANN search: returns node IDs ordered by ascending distance.
   * Uses sqlite-vec KNN syntax: `WHERE embedding MATCH ? ORDER BY distance LIMIT ?`
   */
  search(queryVec, topN = 10) {
    if (!this._available || !this.db) return [];
    try {
      const rows = this.db.prepare(`
        SELECT m.node_id, v.distance
        FROM vec_nodes v
        JOIN vec_nodes_map m ON m.vec_rowid = v.rowid
        WHERE v.embedding MATCH ?
          AND k = ?
        ORDER BY v.distance
      `).all(queryVec, topN);
      return rows.map((r) => r.node_id);
    } catch (err) {
      (0, import_errors.logWarn)("VecIndex: search failed", { error: String(err) });
      return [];
    }
  }
  /** Return all node IDs currently stored in the index. */
  getEmbeddedNodeIds() {
    if (!this._available || !this.db) return [];
    try {
      const rows = this.db.prepare("SELECT node_id FROM vec_nodes_map").all();
      return rows.map((r) => r.node_id);
    } catch {
      return [];
    }
  }
  /** Returns the number of entries currently in the vec index. */
  count() {
    if (!this._available || !this.db) return 0;
    try {
      const row = this.db.prepare("SELECT COUNT(*) as c FROM vec_nodes_map").get();
      return row ? row.c : 0;
    } catch {
      return 0;
    }
  }
  close() {
    if (this.db) {
      try {
        this.db.close();
      } catch {
      }
      this.db = null;
      this._available = false;
    }
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  VecIndex
});
//# sourceMappingURL=vec-index.js.map
