"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 queries_exports = {};
__export(queries_exports, {
  DocsQueries: () => DocsQueries
});
module.exports = __toCommonJS(queries_exports);
var fs = __toESM(require("fs"));
var path = __toESM(require("path"));
var import_vectors = require("./vectors");
class DocsQueries {
  constructor(db, projectRoot, config) {
    this.db = db;
    this.projectRoot = projectRoot;
    this.config = config ?? null;
  }
  // ── TOC ─────────────────────────────────────────────────────────────────────
  /**
   * Get table of contents for a file or the whole project.
   */
  getToc(opts) {
    const where = opts?.file ? "WHERE file_path = ?" : "";
    const params = opts?.file ? [opts.file] : [];
    const rows = this.db.all(`
      SELECT id, title, level, file_path, summary, parent_id
      FROM doc_sections
      ${where}
      ORDER BY file_path, position
    `, params);
    if (!opts?.tree) {
      return rows.map((r) => ({
        id: r.id,
        title: r.title,
        level: r.level,
        filePath: r.file_path,
        summary: r.summary
      }));
    }
    return this.buildTocTree(rows);
  }
  /**
   * Get heading hierarchy for a single document.
   */
  getOutline(file) {
    return this.getToc({ file, tree: true });
  }
  // ── Section Retrieval ───────────────────────────────────────────────────────
  /**
   * Get a section by ID, optionally with context (ancestor chain + child summaries).
   */
  getSection(id, opts) {
    const row = this.db.get("SELECT * FROM doc_sections WHERE id = ?", [id]);
    if (!row) return null;
    const section = this.rowToSection(row);
    const content = this.readSectionContent(section);
    if (!opts?.context) {
      return { section, content };
    }
    const ancestors = [];
    let currentParent = section.parentId;
    while (currentParent) {
      const parent = this.db.get("SELECT id, title, level, parent_id FROM doc_sections WHERE id = ?", [currentParent]);
      if (!parent) break;
      ancestors.unshift({ id: parent.id, title: parent.title, level: parent.level });
      currentParent = parent.parent_id;
    }
    const childRows = this.db.all(
      "SELECT id, title, summary FROM doc_sections WHERE parent_id = ? ORDER BY position",
      [id]
    );
    return { section, content, ancestors, children: childRows };
  }
  // ── Search ──────────────────────────────────────────────────────────────────
  /**
   * Search sections by query using FTS5 + optional vector search (hybrid).
   */
  async searchSections(query, opts) {
    const limit = opts?.limit ?? 10;
    const ftsResults = this.searchFTS(query, opts?.file, limit);
    if (this.config?.enableEmbeddings) {
      try {
        const vectorMgr = new import_vectors.DocsVectorManager(this.config, this.db);
        const vectorResults = await vectorMgr.search(query, limit);
        if (vectorResults.length > 0) {
          const alpha = 0.5;
          const merged = /* @__PURE__ */ new Map();
          for (const r of ftsResults) {
            merged.set(r.section.id, { section: r.section, score: r.score * (1 - alpha), matchType: "fts" });
          }
          for (const vr of vectorResults) {
            const existing = merged.get(vr.sectionId);
            if (existing) {
              existing.score += vr.score * alpha;
              existing.matchType = "semantic";
            } else {
              const row = this.db.get("SELECT * FROM doc_sections WHERE id = ?", [vr.sectionId]);
              if (row) {
                if (opts?.file && row.file_path !== opts.file) continue;
                merged.set(vr.sectionId, {
                  section: this.rowToSection(row),
                  score: vr.score * alpha,
                  matchType: "semantic"
                });
              }
            }
          }
          const sorted = [...merged.values()].sort((a, b) => b.score - a.score).slice(0, limit);
          return sorted;
        }
      } catch {
      }
    }
    return ftsResults;
  }
  /**
   * FTS-only search (used internally and as fallback).
   */
  searchFTS(query, file, limit) {
    const sanitized = query.replace(/[",]/g, " ").replace(/\s+/g, " ").trim();
    if (!sanitized) return [];
    let sql;
    let params;
    if (file) {
      sql = `
        SELECT s.*, rank
        FROM doc_sections_fts fts
        JOIN doc_sections s ON s.id = fts.id
        WHERE doc_sections_fts MATCH ? AND s.file_path = ?
        ORDER BY rank
        LIMIT ?
      `;
      params = [sanitized, file, limit];
    } else {
      sql = `
        SELECT s.*, rank
        FROM doc_sections_fts fts
        JOIN doc_sections s ON s.id = fts.id
        WHERE doc_sections_fts MATCH ?
        ORDER BY rank
        LIMIT ?
      `;
      params = [sanitized, limit];
    }
    try {
      const rows = this.db.all(sql, params);
      return rows.map((row) => ({
        section: this.rowToSection(row),
        score: Math.abs(row.rank ?? 0),
        matchType: "fts"
      }));
    } catch {
      return this.searchFallback(sanitized, file, limit);
    }
  }
  // ── Code Refs ───────────────────────────────────────────────────────────────
  /**
   * Get code symbols referenced by a section, or doc sections that reference a symbol.
   */
  getRefs(opts) {
    if (opts.sectionId) {
      return this.db.all(`
        SELECT r.*, s.title as section_title
        FROM doc_code_refs r
        JOIN doc_sections s ON s.id = r.section_id
        WHERE r.section_id = ?
        ORDER BY r.confidence DESC
      `, [opts.sectionId]).map((r) => ({
        sectionId: r.section_id,
        qualifiedName: r.qualified_name,
        refType: r.ref_type,
        confidence: r.confidence,
        sectionTitle: r.section_title
      }));
    }
    if (opts.qualifiedName) {
      return this.db.all(`
        SELECT r.*, s.title as section_title
        FROM doc_code_refs r
        JOIN doc_sections s ON s.id = r.section_id
        WHERE r.qualified_name = ?
        ORDER BY r.confidence DESC
      `, [opts.qualifiedName]).map((r) => ({
        sectionId: r.section_id,
        qualifiedName: r.qualified_name,
        refType: r.ref_type,
        confidence: r.confidence,
        sectionTitle: r.section_title
      }));
    }
    return [];
  }
  // ── Stats ───────────────────────────────────────────────────────────────────
  getStats() {
    const files = this.db.get("SELECT COUNT(DISTINCT file_path) as cnt FROM doc_sections")?.cnt ?? 0;
    const sections = this.db.get("SELECT COUNT(*) as cnt FROM doc_sections")?.cnt ?? 0;
    const codeRefs = this.db.get("SELECT COUNT(*) as cnt FROM doc_code_refs")?.cnt ?? 0;
    return { files, sections, codeRefs };
  }
  // ── Private ─────────────────────────────────────────────────────────────────
  rowToSection(row) {
    return {
      id: row.id,
      filePath: row.file_path,
      title: row.title,
      level: row.level,
      parentId: row.parent_id ?? null,
      summary: row.summary ?? null,
      byteStart: row.byte_start,
      byteEnd: row.byte_end,
      contentHash: row.content_hash,
      tags: row.tags ? JSON.parse(row.tags) : [],
      position: row.position,
      updatedAt: row.updated_at
    };
  }
  readSectionContent(section) {
    const absPath = path.join(this.projectRoot, section.filePath);
    try {
      const buffer = fs.readFileSync(absPath);
      return buffer.slice(section.byteStart, section.byteEnd).toString("utf8");
    } catch {
      return "(file not found on disk)";
    }
  }
  buildTocTree(rows) {
    const map = /* @__PURE__ */ new Map();
    const roots = [];
    for (const row of rows) {
      const entry = {
        id: row.id,
        title: row.title,
        level: row.level,
        filePath: row.file_path,
        summary: row.summary,
        children: []
      };
      map.set(row.id, entry);
      if (!row.parent_id || !map.has(row.parent_id)) {
        roots.push(entry);
      } else {
        map.get(row.parent_id).children.push(entry);
      }
    }
    return roots;
  }
  searchFallback(query, file, limit) {
    const pattern = `%${query}%`;
    let sql;
    let params;
    if (file) {
      sql = "SELECT * FROM doc_sections WHERE file_path = ? AND (title LIKE ? OR summary LIKE ?) LIMIT ?";
      params = [file, pattern, pattern, limit];
    } else {
      sql = "SELECT * FROM doc_sections WHERE title LIKE ? OR summary LIKE ? LIMIT ?";
      params = [pattern, pattern, limit];
    }
    const rows = this.db.all(sql, params);
    return rows.map((row) => ({
      section: this.rowToSection(row),
      score: 1,
      matchType: "fts"
    }));
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  DocsQueries
});
//# sourceMappingURL=queries.js.map
