"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SessionMemory = void 0;
const database_1 = require("../../06-memory/database/database");
const logger_1 = require("../../06-memory/database/logger");
const context_bridge_1 = require("../context/context-bridge");
const context_continuity_1 = require("../context/context-continuity");
const context_predictor_1 = require("../context/context-predictor");
const PROJECT_DIR = process.cwd(); // SessionMemory always runs from project root
class SessionMemory {
    constructor() {
        (0, database_1.initializeDatabase)();
    }
    startSession(toolName, project) {
        const db = (0, database_1.getDb)();
        const now = new Date().toISOString();
        // Supreme: Consume previous session bridge if available
        const prevBridge = (0, context_bridge_1.consumeSessionBridge)(PROJECT_DIR, -1);
        // Also detect/create continuity thread
        (0, context_continuity_1.detectOrCreateThread)(PROJECT_DIR, project, [], []);
        const result = db.prepare('INSERT INTO sessions (tool_name, project, start_time, files_touched, key_decisions, context_snapshot) VALUES (?, ?, ?, ?, ?, ?)').run(toolName, project, now, '[]', '[]', prevBridge?.summary || '');
        return Number(result.lastInsertRowid);
    }
    endSession(sessionId, params) {
        const db = (0, database_1.getDb)();
        const now = new Date().toISOString();
        // Get session info for bridge
        const session = db.prepare('SELECT tool_name, project FROM sessions WHERE id = ?').get(sessionId);
        // Supreme: Capture rich session bridge for next session
        if (session) {
            // Get approaches from this session
            let approaches = [];
            try {
                approaches = db.prepare('SELECT approach, status FROM session_approaches WHERE session_id = ?').all(sessionId);
            }
            catch { }
            // Get questions
            let questions = [];
            try {
                questions = db.prepare('SELECT question, CASE WHEN resolved THEN 1 ELSE 0 END as resolved FROM session_questions WHERE session_id = ?').all(sessionId);
            }
            catch { }
            const files = params.filesTouched || [];
            const decisions = params.keyDecisions || [];
            // Predict next context
            const predictionState = (0, context_predictor_1.predictContext)(session.project, PROJECT_DIR);
            (0, context_bridge_1.captureSessionBridge)(PROJECT_DIR, {
                sessionId,
                project: session.project,
                tool: session.tool_name || 'unknown',
                summary: params.contextSnapshot || decisions.slice(0, 3).join('; ') || 'Session completed.',
                status: 'completed',
                filesTouched: files,
                keyDecisions: decisions,
                openQuestions: questions.filter((q) => !q.resolved).map((q) => q.question),
                failedApproaches: approaches.filter((a) => a.status === 'failed' || a.status === 'rejected').map((a) => a.approach),
                workingApproaches: approaches.filter((a) => a.status === 'accepted' || a.status === 'worked').map((a) => a.approach),
                lastThought: decisions.slice(-3).join('; ') || 'No explicit closing thought.',
                predictedNextSteps: (0, context_predictor_1.bridgeWithPredictions)(predictionState.predictions.filter(p => p.confidence >= 70).map(p => p.text), predictionState),
            });
            // Supreme: Capture continuity thread
            (0, context_continuity_1.captureSessionEnd)(PROJECT_DIR, session.project, decisions, files, approaches, questions);
            (0, context_continuity_1.updateFileFocus)(PROJECT_DIR, files);
        }
        db.prepare('UPDATE sessions SET end_time = ?, files_touched = ?, key_decisions = ?, context_snapshot = ? WHERE id = ?').run(now, JSON.stringify(params.filesTouched || []), JSON.stringify(params.keyDecisions || []), params.contextSnapshot || '', sessionId);
    }
    recordDecision(params) {
        const db = (0, database_1.getDb)();
        const result = db.prepare('INSERT INTO decisions (technology, reason, outcome, was_right, project) VALUES (?, ?, ?, ?, ?)').run(params.technology, params.reason, params.outcome || '', params.wasRight === undefined ? null : (params.wasRight ? 1 : 0), params.project);
        if (params.sessionId) {
            try {
                const row = db.prepare('SELECT key_decisions FROM sessions WHERE id = ?').get(params.sessionId);
                if (row) {
                    const decisions = JSON.parse(row.key_decisions || '[]');
                    decisions.push(`${params.technology}: ${params.reason}`);
                    db.prepare('UPDATE sessions SET key_decisions = ? WHERE id = ?').run(JSON.stringify(decisions.slice(-20)), params.sessionId);
                }
            }
            catch (e) {
                logger_1.logger.warn('recordDecision: ' + String(e));
            }
        }
        return Number(result.lastInsertRowid);
    }
    recordBug(params) {
        const db = (0, database_1.getDb)();
        const now = new Date().toISOString();
        try {
            db.exec('ALTER TABLE behavior_events ADD COLUMN recurrence_count INTEGER DEFAULT 0');
        }
        catch { /* column may already exist */ }
        try {
            const existing = db.prepare('SELECT id, recurrence_count FROM behavior_events WHERE event_type = ? AND file_path = ? AND description = ? ORDER BY created_at DESC LIMIT 1').get('bug_fix', params.filePath, params.rootCause);
            let recurrence = 1;
            if (existing) {
                recurrence = (Number(existing.recurrence_count) || 0) + 1;
                db.prepare('UPDATE behavior_events SET recurrence_count = ? WHERE id = ?').run(recurrence, existing.id);
            }
            const result = db.prepare('INSERT INTO behavior_events (event_type, project, file_path, description, severity, evidence, created_at, recurrence_count) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run('bug_fix', params.project, params.filePath, params.rootCause, 'medium', JSON.stringify(params), now, recurrence);
            return Number(result.lastInsertRowid);
        }
        catch {
            const result = db.prepare('INSERT INTO behavior_events (event_type, project, file_path, description, severity, evidence, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)').run('bug_fix', params.project, params.filePath, params.rootCause, 'medium', JSON.stringify(params), now);
            return Number(result.lastInsertRowid);
        }
    }
    getBugHistory(project) {
        const db = (0, database_1.getDb)();
        const rows = db.prepare(project
            ? "SELECT * FROM behavior_events WHERE event_type = 'bug_fix' AND project = ? ORDER BY created_at DESC LIMIT 50"
            : "SELECT * FROM behavior_events WHERE event_type = 'bug_fix' ORDER BY created_at DESC LIMIT 50").all(project || undefined);
        return rows.map((r) => {
            const evidence = safeJson(String(r.evidence));
            return {
                id: Number(r.id),
                type: 'bug_fix',
                location: String(r.file_path || ''),
                rootCause: String(r.description || ''),
                fix: String(evidence?.fix || ''),
                timeMinutes: Number(evidence?.timeMinutes || 0),
                preventable: Boolean(evidence?.preventable || false),
                project: String(r.project || ''),
                filePath: String(r.file_path || ''),
                occurredAt: String(r.created_at || ''),
                solvedAt: String(r.resolved_at || r.created_at || ''),
                recurrenceCount: 0,
            };
        });
    }
    getRepeatBugs() {
        const db = (0, database_1.getDb)();
        try {
            const rows = db.prepare("SELECT description, file_path, recurrence_count, COUNT(*) as cnt FROM behavior_events WHERE event_type = 'bug_fix' GROUP BY description HAVING cnt > 1 ORDER BY cnt DESC LIMIT 10").all();
            const grouped = new Map();
            for (const r of rows) {
                const existing = grouped.get(r.description);
                if (existing) {
                    existing.count += r.cnt;
                    if (!existing.files.includes(r.file_path))
                        existing.files.push(r.file_path);
                }
                else {
                    grouped.set(r.description, { count: r.cnt, files: [r.file_path] });
                }
            }
            return [...grouped.entries()]
                .map(([desc, data]) => ({ description: desc, count: data.count, files: data.files }))
                .sort((a, b) => b.count - a.count);
        }
        catch {
            return [];
        }
    }
    getDecisionHistory(project) {
        const db = (0, database_1.getDb)();
        const rows = db.prepare(project
            ? 'SELECT * FROM decisions WHERE project = ? ORDER BY created_at DESC LIMIT 50'
            : 'SELECT * FROM decisions ORDER BY created_at DESC LIMIT 50').all(project || undefined);
        return rows.map((r) => ({
            id: Number(r.id),
            technology: String(r.technology || ''),
            reason: String(r.reason || ''),
            outcome: String(r.outcome || ''),
            wasRight: r.was_right === null ? null : Boolean(r.was_right),
            project: String(r.project || ''),
            createdAt: String(r.created_at || ''),
        }));
    }
    getDecisionSummary() {
        const db = (0, database_1.getDb)();
        const rows = db.prepare('SELECT technology, COUNT(*) as times, SUM(CASE WHEN was_right = 1 THEN 1 ELSE 0 END) as right_count FROM decisions GROUP BY technology ORDER BY times DESC').all();
        return rows.map((r) => ({
            technology: r.technology,
            times: r.times,
            wasRightPct: r.times > 0 ? Math.round((r.right_count / r.times) * 100) : 0,
        }));
    }
    getRecentSessions(limit = 10) {
        const db = (0, database_1.getDb)();
        const rows = db.prepare('SELECT * FROM sessions ORDER BY start_time DESC LIMIT ?').all(limit);
        return rows.map(mapSessionRow);
    }
    getSessionsByTool(toolName, limit = 10) {
        const db = (0, database_1.getDb)();
        const rows = db.prepare('SELECT * FROM sessions WHERE tool_name = ? ORDER BY start_time DESC LIMIT ?').all(toolName, limit);
        return rows.map(mapSessionRow);
    }
    buildContextChain(project, maxSessions = 5) {
        const sessions = this.getRecentSessions(maxSessions);
        const commonFiles = new Set();
        const recurringDecisions = new Map();
        for (const s of sessions) {
            for (const f of s.filesTouched)
                commonFiles.add(f);
            for (const d of s.keyDecisions) {
                recurringDecisions.set(d, (recurringDecisions.get(d) || 0) + 1);
            }
        }
        const progression = sessions.length > 0
            ? `Started with ${sessions[sessions.length - 1].toolName} → most recently used ${sessions[0].toolName} (${sessions.length} sessions total)`
            : 'No session history yet';
        return {
            sessions: sessions.reverse(),
            commonFiles: [...commonFiles],
            recurringDecisions: [...recurringDecisions.entries()]
                .filter(([, count]) => count > 1)
                .map(([d]) => d),
            progression,
        };
    }
    searchSessions(query, limit = 10) {
        const db = (0, database_1.getDb)();
        const rows = db.prepare("SELECT * FROM sessions WHERE key_decisions LIKE ? OR context_snapshot LIKE ? OR project LIKE ? ORDER BY start_time DESC LIMIT ?").all(`%${query}%`, `%${query}%`, `%${query}%`, limit);
        return rows.map((r) => {
            const decisions = safeJson(String(r.key_decisions)) || [];
            const ctx = String(r.context_snapshot || '');
            const matches = [];
            for (const d of decisions) {
                if (d.toLowerCase().includes(query.toLowerCase()))
                    matches.push(`Decision: ${d}`);
            }
            if (ctx.toLowerCase().includes(query.toLowerCase()))
                matches.push('Context: ' + ctx.slice(0, 80));
            if (String(r.project || '').toLowerCase().includes(query.toLowerCase()))
                matches.push(`Project: ${r.project}`);
            return {
                session: mapSessionRow(r),
                score: matches.length,
                matches: matches.slice(0, 5),
            };
        }).sort((a, b) => b.score - a.score);
    }
    getLastSessionForProject(project) {
        const db = (0, database_1.getDb)();
        const row = db.prepare('SELECT * FROM sessions WHERE project = ? AND end_time IS NOT NULL ORDER BY end_time DESC LIMIT 1').get(project);
        return row ? mapSessionRow(row) : null;
    }
    getSessionStats() {
        const db = (0, database_1.getDb)();
        const total = db.prepare('SELECT COUNT(*) as count FROM sessions').get().count;
        const byTool = db.prepare('SELECT tool_name, COUNT(*) as count FROM sessions GROUP BY tool_name ORDER BY count DESC').all();
        const byProject = db.prepare('SELECT project, COUNT(*) as count FROM sessions GROUP BY project ORDER BY count DESC').all();
        const avgDuration = db.prepare("SELECT AVG(strftime('%s', end_time) - strftime('%s', start_time)) / 60 as avg_min FROM sessions WHERE end_time IS NOT NULL").get();
        return {
            totalSessions: total,
            byTool,
            byProject,
            avgSessionMinutes: Math.round(avgDuration?.avg_min || 0),
        };
    }
    recordApproach(params) {
        const db = (0, database_1.getDb)();
        const result = db.prepare('INSERT INTO session_approaches (session_id, project, approach, status, reason) VALUES (?, ?, ?, ?, ?)').run(params.sessionId || null, params.project, params.approach, params.status || 'tried', params.reason || null);
        return Number(result.lastInsertRowid);
    }
    getSessionApproaches(sessionId) {
        const db = (0, database_1.getDb)();
        const rows = db.prepare('SELECT * FROM session_approaches WHERE session_id = ? ORDER BY created_at DESC').all(sessionId);
        return rows.map(mapApproachRow);
    }
    getRecentApproaches(project, limit = 20) {
        const db = (0, database_1.getDb)();
        const rows = db.prepare(`SELECT approach, status, COUNT(*) as count, MAX(reason) as last_reason, MAX(created_at) as last_seen
       FROM session_approaches
       WHERE project = ?
       GROUP BY LOWER(approach)
       ORDER BY count DESC, last_seen DESC
       LIMIT ?`).all(project, limit);
        return rows.map(r => ({
            approach: r.approach,
            status: r.status,
            count: r.count,
            lastReason: r.last_reason,
            lastSeen: r.last_seen,
        }));
    }
    recordFileTouch(params) {
        const db = (0, database_1.getDb)();
        const existing = db.prepare('SELECT id, touch_count FROM session_files WHERE session_id IS ? AND file_path = ? LIMIT 1').get(params.sessionId || null, params.filePath);
        if (existing) {
            db.prepare('UPDATE session_files SET touch_count = touch_count + 1, last_touched = datetime(\'now\') WHERE id = ?').run(existing.id);
        }
        else {
            db.prepare('INSERT INTO session_files (session_id, project, file_path) VALUES (?, ?, ?)').run(params.sessionId || null, params.project, params.filePath);
        }
    }
    getSessionFiles(sessionId) {
        const db = (0, database_1.getDb)();
        const rows = db.prepare('SELECT * FROM session_files WHERE session_id = ? ORDER BY touch_count DESC, last_touched DESC').all(sessionId);
        return rows.map(mapFileRow);
    }
    getMostTouchedFiles(project, limit = 10) {
        const db = (0, database_1.getDb)();
        const rows = db.prepare(`SELECT file_path,
              SUM(touch_count) as total_touches,
              COUNT(DISTINCT session_id) as session_count,
              MAX(last_touched) as last_touched
       FROM session_files
       WHERE project = ?
       GROUP BY file_path
       ORDER BY total_touches DESC, last_touched DESC
       LIMIT ?`).all(project, limit);
        return rows.map(r => ({
            filePath: r.file_path,
            touchCount: r.total_touches,
            sessionCount: r.session_count,
            lastTouched: r.last_touched,
        }));
    }
    recordQuestion(params) {
        const db = (0, database_1.getDb)();
        const result = db.prepare('INSERT INTO session_questions (session_id, project, question, priority) VALUES (?, ?, ?, ?)').run(params.sessionId || null, params.project, params.question, params.priority || 'medium');
        return Number(result.lastInsertRowid);
    }
    resolveQuestion(questionId, answer) {
        const db = (0, database_1.getDb)();
        db.prepare('UPDATE session_questions SET resolved = 1, answer = ?, resolved_at = datetime(\'now\') WHERE id = ?').run(answer, questionId);
    }
    getOpenQuestions(project, includeResolved = false) {
        const db = (0, database_1.getDb)();
        const query = includeResolved
            ? 'SELECT * FROM session_questions WHERE project = ? ORDER BY resolved ASC, created_at DESC LIMIT 50'
            : 'SELECT * FROM session_questions WHERE project = ? AND resolved = 0 ORDER BY CASE priority WHEN \'high\' THEN 1 WHEN \'medium\' THEN 2 ELSE 3 END, created_at DESC LIMIT 50';
        const rows = db.prepare(query).all(project);
        return rows.map(mapQuestionRow);
    }
}
exports.SessionMemory = SessionMemory;
function mapSessionRow(r) {
    return {
        id: Number(r.id),
        toolName: String(r.tool_name || ''),
        project: String(r.project || ''),
        startTime: String(r.start_time || ''),
        endTime: r.end_time ? String(r.end_time) : undefined,
        filesTouched: safeJson(String(r.files_touched)) || [],
        keyDecisions: safeJson(String(r.key_decisions)) || [],
        contextSnapshot: String(r.context_snapshot || ''),
    };
}
function mapApproachRow(r) {
    return {
        id: Number(r.id),
        sessionId: r.session_id ? Number(r.session_id) : null,
        project: String(r.project || ''),
        approach: String(r.approach || ''),
        status: String(r.status || 'tried'),
        reason: r.reason ? String(r.reason) : null,
        createdAt: String(r.created_at || ''),
    };
}
function mapFileRow(r) {
    return {
        id: Number(r.id),
        sessionId: r.session_id ? Number(r.session_id) : null,
        project: String(r.project || ''),
        filePath: String(r.file_path || ''),
        touchCount: Number(r.touch_count || 1),
        firstTouched: String(r.first_touched || ''),
        lastTouched: String(r.last_touched || ''),
    };
}
function mapQuestionRow(r) {
    return {
        id: Number(r.id),
        sessionId: r.session_id ? Number(r.session_id) : null,
        project: String(r.project || ''),
        question: String(r.question || ''),
        priority: String(r.priority || 'medium'),
        resolved: Boolean(r.resolved),
        answer: r.answer ? String(r.answer) : null,
        createdAt: String(r.created_at || ''),
        resolvedAt: r.resolved_at ? String(r.resolved_at) : null,
    };
}
function safeJson(val) {
    if (!val || val === '[]' || val === '{}')
        return null;
    try {
        return JSON.parse(val);
    }
    catch {
        return val;
    }
}
//# sourceMappingURL=session-memory.js.map