import { init_transcript_paths, resolveSessionFilePath } from "./parity/transcript-paths.js";
import { FILENAMES, init_paths } from "../config/paths.js";
import { isTranscriptContextEntry } from "./session-context-for-llm.js";
import { readTranscriptRowsFromFile, rowsToLlmMessages } from "./parity/jsonl-transcript-io.js";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
//#region src/session/search-index.ts
/**
* In-memory inverted index over session transcripts (`sessions.json` + JSONL).
*/
init_paths();
init_transcript_paths();
var SessionSearchIndex = class {
	sessions = /* @__PURE__ */ new Map();
	globalWordIndex = /* @__PURE__ */ new Map();
	/**
	* Scan `sessionsRoot` (flat `sessions.json` + per-session `.jsonl` transcripts).
	*/
	async buildIndex(sessionsRoot) {
		this.sessions.clear();
		this.globalWordIndex.clear();
		const mapPath = join(sessionsRoot, FILENAMES.SESSIONS_MAP);
		let raw;
		try {
			raw = await readFile(mapPath, "utf-8");
		} catch {
			return;
		}
		let map;
		try {
			const parsed = JSON.parse(raw);
			if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
			map = parsed;
		} catch {
			return;
		}
		for (const [sessionKey, entry] of Object.entries(map)) {
			if (!entry?.sessionId) continue;
			try {
				const rows = await readTranscriptRowsFromFile(resolveSessionFilePath(entry.sessionId, entry, { sessionsDir: sessionsRoot }));
				const messages = rowsToLlmMessages(rows);
				const wordIndex = this.buildWordIndex(messages);
				this.mergeContextTextIntoWordIndex(wordIndex, rows, messages.length);
				const indexed = {
					key: sessionKey,
					messages,
					wordIndex
				};
				this.sessions.set(sessionKey, indexed);
				this.mergeIntoGlobalIndex(sessionKey, wordIndex);
			} catch {}
		}
	}
	search(query, limit = 10) {
		const queryWords = tokenizeWords(query);
		if (queryWords.length === 0) return [];
		const scores = /* @__PURE__ */ new Map();
		for (const word of queryWords) {
			const matchingSessions = this.globalWordIndex.get(word);
			if (!matchingSessions) continue;
			for (const sessionKey of matchingSessions) scores.set(sessionKey, (scores.get(sessionKey) || 0) + 1);
		}
		return Array.from(scores.entries()).map(([key, score]) => ({
			key,
			score: score / queryWords.length
		})).sort((a, b) => b.score - a.score).slice(0, limit);
	}
	getSessionMessages(key) {
		return this.sessions.get(key)?.messages ?? [];
	}
	buildWordIndex(messages) {
		const index = /* @__PURE__ */ new Map();
		for (let i = 0; i < messages.length; i++) {
			const words = tokenizeWords(extractIndexableText(messages[i].content));
			for (const word of words) {
				if (!index.has(word)) index.set(word, /* @__PURE__ */ new Set());
				index.get(word).add(i);
			}
		}
		return index;
	}
	mergeContextTextIntoWordIndex(wordIndex, rows, llmMessageCount) {
		let slot = 0;
		for (const r of rows) {
			if (!isTranscriptContextEntry(r)) continue;
			const parts = [];
			if (typeof r.text === "string" && r.text.trim()) parts.push(r.text);
			if (typeof r.id === "string" && r.id.trim()) parts.push(r.id);
			const blob = parts.join(" ");
			if (!blob.trim()) continue;
			const words = tokenizeWords(blob);
			const idx = llmMessageCount + slot;
			slot += 1;
			for (const word of words) {
				if (!wordIndex.has(word)) wordIndex.set(word, /* @__PURE__ */ new Set());
				wordIndex.get(word).add(idx);
			}
		}
	}
	mergeIntoGlobalIndex(sessionKey, wordIndex) {
		for (const word of wordIndex.keys()) {
			if (!this.globalWordIndex.has(word)) this.globalWordIndex.set(word, /* @__PURE__ */ new Set());
			this.globalWordIndex.get(word).add(sessionKey);
		}
	}
};
function tokenizeWords(text) {
	return text.toLowerCase().split(/[\W_]+/).map((w) => w.trim()).filter(Boolean);
}
function extractIndexableText(content) {
	if (typeof content === "string") return content;
	if (!Array.isArray(content)) return "";
	const parts = [];
	for (const item of content) {
		if (typeof item !== "object" || item === null || !("type" in item)) continue;
		const c = item;
		if (c.type === "text" && typeof c.text === "string") parts.push(c.text);
	}
	return parts.join(" ");
}
//#endregion
export { SessionSearchIndex };

//# sourceMappingURL=search-index.js.map