"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Logger = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const crypto_1 = __importDefault(require("crypto"));
const node_sqlite_1 = require("node:sqlite");
const parser_1 = require("../config/parser");
const paths_1 = require("../config/paths");
class Logger {
    db;
    constructor() {
        const config = (0, parser_1.loadConfig)() || {};
        let dbPath = (config && config.memory && config.memory.path) ? config.memory.path : 'memory.db';
        if (dbPath.endsWith('.json')) {
            dbPath = dbPath.replace('.json', '.db');
        }
        const fullPath = (0, paths_1.getPath)(dbPath);
        // Ensure directory exists
        const dir = path_1.default.dirname(fullPath);
        if (!fs_1.default.existsSync(dir)) {
            fs_1.default.mkdirSync(dir, { recursive: true });
        }
        this.db = new node_sqlite_1.DatabaseSync(fullPath);
        this.initDb();
    }
    initDb() {
        this.db.exec('PRAGMA journal_mode = WAL;');
        this.db.exec('PRAGMA synchronous = NORMAL;');
        this.db.exec('PRAGMA busy_timeout = 5000;');
        this.db.exec(`
      CREATE TABLE IF NOT EXISTS sessions (
        id TEXT PRIMARY KEY,
        title TEXT NOT NULL,
        timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
      )
    `);
        this.db.exec(`
      CREATE TABLE IF NOT EXISTS messages (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        session_id TEXT,
        role TEXT NOT NULL,
        content TEXT NOT NULL,
        name TEXT,
        tool_call_id TEXT,
        tool_calls TEXT,
        timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
      )
    `);
        // Phase 1: SQLite Index Optimization
        this.db.exec(`
      CREATE INDEX IF NOT EXISTS idx_session_id ON messages(session_id);
    `);
        // Ensure session_id exists for older DBs
        try {
            this.db.prepare('ALTER TABLE messages ADD COLUMN session_id TEXT').run();
        }
        catch (e) {
            // Column probably already exists
        }
        // Migration logic from old memory.json to SQLite
        const config = (0, parser_1.loadConfig)() || {};
        const oldJsonPath = (0, paths_1.getPath)((config && config.memory && config.memory.path) ? config.memory.path : 'memory.json');
        const countRow = this.db.prepare('SELECT COUNT(*) as count FROM messages').get();
        if (countRow.count === 0 && fs_1.default.existsSync(oldJsonPath)) {
            try {
                const data = fs_1.default.readFileSync(oldJsonPath, 'utf-8');
                const oldMemory = JSON.parse(data);
                if (Array.isArray(oldMemory) && oldMemory.length > 0) {
                    const insert = this.db.prepare(`
            INSERT INTO messages (role, content, name, tool_call_id, tool_calls)
            VALUES (@role, @content, @name, @tool_call_id, @tool_calls)
          `);
                    const insertMany = (entries) => {
                        this.db.exec('BEGIN TRANSACTION');
                        try {
                            for (const entry of entries) {
                                insert.run({
                                    role: entry.role,
                                    content: entry.content || '',
                                    name: entry.name || null,
                                    tool_call_id: entry.tool_call_id || null,
                                    tool_calls: entry.tool_calls ? JSON.stringify(entry.tool_calls) : null
                                });
                            }
                            this.db.exec('COMMIT');
                        }
                        catch (e) {
                            this.db.exec('ROLLBACK');
                            throw e;
                        }
                    };
                    insertMany(oldMemory);
                    console.log('[Nyxora Memory] Successfully migrated memory.json to SQLite database (Atomic Storage).');
                    // Rename old file to prevent re-migration issues and keep as backup
                    fs_1.default.renameSync(oldJsonPath, oldJsonPath + '.bak');
                }
            }
            catch (error) {
                console.error('[Nyxora Memory] Failed to migrate old memory.json:', error);
            }
        }
    }
    getSessions() {
        const rows = this.db.prepare('SELECT id, title, timestamp FROM sessions ORDER BY timestamp DESC').all();
        return rows;
    }
    createSession(title) {
        const id = crypto_1.default.randomUUID();
        this.db.prepare('INSERT INTO sessions (id, title) VALUES (?, ?)').run(id, title);
        return id;
    }
    deleteSession(sessionId) {
        this.db.prepare('DELETE FROM messages WHERE session_id = ?').run(sessionId);
        this.db.prepare('DELETE FROM sessions WHERE id = ?').run(sessionId);
    }
    renameSession(sessionId, newTitle) {
        this.db.prepare('UPDATE sessions SET title = ? WHERE id = ?').run(newTitle, sessionId);
    }
    getHistory(sessionId) {
        let rows;
        // Phase 2: Sliding Window Algorithm (LLM Context Limit)
        // Fetch only the last 40 messages, then order them chronologically
        if (sessionId) {
            rows = this.db.prepare(`
        SELECT * FROM (
          SELECT role, content, name, tool_call_id, tool_calls, session_id, id 
          FROM messages 
          WHERE session_id = ? 
          ORDER BY id DESC LIMIT 40
        ) ORDER BY id ASC
      `).all(sessionId);
        }
        else {
            rows = this.db.prepare(`
        SELECT * FROM (
          SELECT role, content, name, tool_call_id, tool_calls, session_id, id 
          FROM messages 
          WHERE session_id IS NULL 
          ORDER BY id DESC LIMIT 40
        ) ORDER BY id ASC
      `).all();
        }
        return rows.map((row) => {
            const entry = {
                role: row.role,
                content: row.content,
            };
            if (row.name)
                entry.name = row.name;
            if (row.tool_call_id)
                entry.tool_call_id = row.tool_call_id;
            if (row.tool_calls)
                entry.tool_calls = JSON.parse(row.tool_calls);
            if (row.session_id)
                entry.session_id = row.session_id;
            return entry;
        });
    }
    addEntry(entry, sessionId) {
        const insert = this.db.prepare(`
      INSERT INTO messages (session_id, role, content, name, tool_call_id, tool_calls)
      VALUES (@session_id, @role, @content, @name, @tool_call_id, @tool_calls)
    `);
        insert.run({
            session_id: sessionId || null,
            role: entry.role,
            content: entry.content || '',
            name: entry.name || null,
            tool_call_id: entry.tool_call_id || null,
            tool_calls: entry.tool_calls ? JSON.stringify(entry.tool_calls) : null
        });
    }
    clear(sessionId) {
        if (sessionId) {
            this.db.prepare('DELETE FROM messages WHERE session_id = ?').run(sessionId);
        }
        else {
            this.db.prepare('DELETE FROM messages WHERE session_id IS NULL').run();
        }
    }
}
exports.Logger = Logger;
