import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import { DatabaseSync } from "node:sqlite";
//#region klaw-memory/session-search.js
const MEMORY_DIR = process.env.KLAW_MEMORY_DIR ?? process.env.KODELYTH_MEMORY_DIR ?? path.join(os.homedir(), ".klaw", "memory");
const DB_PATH = path.join(MEMORY_DIR, "sessions.db");
/** @type {DatabaseSync | null} */
let _db = null;
function getDb() {
	if (_db) return _db;
	fs.mkdirSync(MEMORY_DIR, { recursive: true });
	_db = new DatabaseSync(DB_PATH);
	_db.exec("PRAGMA journal_mode = WAL;");
	_db.exec("PRAGMA synchronous = NORMAL;");
	_db.exec(`
    CREATE VIRTUAL TABLE IF NOT EXISTS messages USING fts5(
      session_id UNINDEXED,
      role       UNINDEXED,
      content,
      timestamp  UNINDEXED,
      channel    UNINDEXED,
      tokenize = 'porter unicode61'
    );

    CREATE TABLE IF NOT EXISTS session_summaries (
      session_id    TEXT PRIMARY KEY,
      summary       TEXT,
      started_at    TEXT,
      ended_at      TEXT,
      message_count INTEGER
    );
  `);
	return _db;
}
/**
* Index a single message into the FTS5 table.
*
* @param {string} sessionId  - Unique session identifier
* @param {'user'|'assistant'|'tool'} role
* @param {string} content    - Message text
* @param {string} [channel]  - Channel name (telegram, slack, etc.)
*/
function indexMessage(sessionId, role, content, channel = "") {
	if (!content?.trim()) return;
	getDb().prepare("INSERT INTO messages (session_id, role, content, timestamp, channel) VALUES (?, ?, ?, ?, ?)").run(sessionId, role, String(content), (/* @__PURE__ */ new Date()).toISOString(), String(channel));
}
/**
* Store or update a session summary (upsert).
*
* @param {string} sessionId
* @param {string} summary
* @param {string} startedAt  - ISO 8601
* @param {string} endedAt    - ISO 8601
* @param {number} messageCount
*/
function indexSessionSummary(sessionId, summary, startedAt, endedAt, messageCount) {
	getDb().prepare(`
    INSERT INTO session_summaries (session_id, summary, started_at, ended_at, message_count)
    VALUES (?, ?, ?, ?, ?)
    ON CONFLICT(session_id) DO UPDATE SET
      summary       = excluded.summary,
      started_at    = excluded.started_at,
      ended_at      = excluded.ended_at,
      message_count = excluded.message_count
  `).run(sessionId, summary, startedAt, endedAt, messageCount);
}
/**
* Full-text search across all indexed messages.
*
* Supports FTS5 query syntax:
*   "authentication bug"     — phrase search
*   auth* AND session        — boolean
*   session_id:abc123        — column filter (not recommended; use sessionId option)
*
* @param {string} query
* @param {{ limit?: number; role?: string; channel?: string }} [options]
* @returns {Array<{session_id, role, content, timestamp, channel, preview, rank}>}
*/
function searchSessions(query, options = {}) {
	if (!query?.trim()) return [];
	const { limit = 10, role, channel } = options;
	const db = getDb();
	const filters = [];
	const params = [query];
	if (role) {
		filters.push("role = ?");
		params.push(role);
	}
	if (channel) {
		filters.push("channel = ?");
		params.push(channel);
	}
	const whereExtra = filters.length > 0 ? " AND " + filters.join(" AND ") : "";
	params.push(limit);
	return db.prepare(`
    SELECT
      session_id,
      role,
      content,
      timestamp,
      channel,
      snippet(messages, 2, '<mark>', '</mark>', '...', 32) AS preview,
      rank
    FROM messages
    WHERE messages MATCH ?${whereExtra}
    ORDER BY rank
    LIMIT ?
  `).all(...params);
}
/**
* Retrieve a session summary by session ID.
*
* @param {string} sessionId
* @returns {{ session_id, summary, started_at, ended_at, message_count } | null}
*/
function getSessionSummary(sessionId) {
	return getDb().prepare("SELECT * FROM session_summaries WHERE session_id = ?").get(sessionId) ?? null;
}
/**
* Returns all summaries ordered by most recent end time.
*
* @param {{ limit?: number }} [options]
*/
function listSessionSummaries(options = {}) {
	const { limit = 20 } = options;
	return getDb().prepare("SELECT * FROM session_summaries ORDER BY ended_at DESC LIMIT ?").all(limit);
}
/**
* Delete all messages for a given session ID (e.g. for privacy / data purge).
*
* @param {string} sessionId
* @returns {number} rows deleted
*/
function deleteSession(sessionId) {
	const db = getDb();
	const { changes } = db.prepare("DELETE FROM messages WHERE session_id = ?").run(sessionId);
	db.prepare("DELETE FROM session_summaries WHERE session_id = ?").run(sessionId);
	return changes;
}
//#endregion
export { indexSessionSummary as a, indexMessage as i, deleteSession as n, listSessionSummaries as o, getSessionSummary as r, searchSessions as s, DB_PATH as t };
