"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ALL_EVENT_TYPES = void 0;
exports.recordFileSave = recordFileSave;
exports.recordFileCreate = recordFileCreate;
exports.recordFileDelete = recordFileDelete;
exports.recordFileRename = recordFileRename;
exports.recordCursorMove = recordCursorMove;
exports.recordFileFocus = recordFileFocus;
exports.recordFileBlur = recordFileBlur;
exports.recordTerminalCommand = recordTerminalCommand;
exports.recordTerminalCommandDone = recordTerminalCommandDone;
exports.recordTestRun = recordTestRun;
exports.recordTestPass = recordTestPass;
exports.recordTestFail = recordTestFail;
exports.recordBuildStart = recordBuildStart;
exports.recordBuildEnd = recordBuildEnd;
exports.recordError = recordError;
exports.recordGitCommit = recordGitCommit;
exports.recordGitBranch = recordGitBranch;
exports.recordAIPrompt = recordAIPrompt;
exports.recordAIResponse = recordAIResponse;
exports.recordSessionStart = recordSessionStart;
exports.recordSessionEnd = recordSessionEnd;
exports.recordPackageChange = recordPackageChange;
exports.getTimeline = getTimeline;
exports.getEventCounts = getEventCounts;
exports.getLastEventForFile = getLastEventForFile;
exports.getMostRecentEvents = getMostRecentEvents;
exports.linkSessionToRecentEvents = linkSessionToRecentEvents;
exports.unlinkSessionEvents = unlinkSessionEvents;
const database_1 = require("../../06-memory/database/database");
const logger_1 = require("../../06-memory/database/logger");
exports.ALL_EVENT_TYPES = [
    'file_save', 'file_create', 'file_delete', 'file_rename',
    'git_commit', 'package_change',
    'cursor_move', 'file_focus', 'file_blur',
    'terminal_command', 'terminal_command_done',
    'test_run', 'test_pass', 'test_fail',
    'build_start', 'build_end', 'error',
    'git_branch', 'ai_prompt', 'ai_response',
    'session_start', 'session_end',
];
// ─── Schema Migration (idempotent) ─────────────────────────────────────────
let _schemaReady = false;
function ensureSchema() {
    if (_schemaReady)
        return;
    (0, database_1.initializeDatabase)();
    const db = (0, database_1.getDb)();
    // Add new columns to live_events if they don't exist
    const existingCols = db.prepare("PRAGMA table_info(live_events)").all();
    const colNames = new Set(existingCols.map(c => c.name));
    if (!colNames.has('session_id')) {
        db.exec('ALTER TABLE live_events ADD COLUMN session_id INTEGER');
        db.exec('CREATE INDEX IF NOT EXISTS idx_live_events_session ON live_events(session_id)');
    }
    if (!colNames.has('line')) {
        db.exec('ALTER TABLE live_events ADD COLUMN line INTEGER');
    }
    if (!colNames.has('column_pos')) {
        db.exec('ALTER TABLE live_events ADD COLUMN column_pos INTEGER');
    }
    if (!colNames.has('command')) {
        db.exec('ALTER TABLE live_events ADD COLUMN command TEXT');
    }
    if (!colNames.has('exit_code')) {
        db.exec('ALTER TABLE live_events ADD COLUMN exit_code INTEGER');
    }
    if (!colNames.has('duration_ms')) {
        db.exec('ALTER TABLE live_events ADD COLUMN duration_ms INTEGER');
    }
    if (!colNames.has('success')) {
        db.exec('ALTER TABLE live_events ADD COLUMN success INTEGER');
    }
    // Create the full replay view (joined sessions + events for fast queries)
    db.exec(`
    CREATE VIEW IF NOT EXISTS v_session_timeline AS
    SELECT
      e.id AS event_id,
      e.session_id,
      e.project,
      e.event_type,
      e.file_path,
      e.line,
      e.column_pos,
      e.command,
      e.exit_code,
      e.duration_ms,
      e.success,
      e.metadata,
      e.created_at AS event_time,
      s.tool_name AS session_tool,
      s.start_time AS session_start,
      s.end_time AS session_end,
      s.context_snapshot AS session_context
    FROM live_events e
    LEFT JOIN sessions s ON s.id = e.session_id
  `);
    _schemaReady = true;
}
function recordEvent(params) {
    try {
        ensureSchema();
        const db = (0, database_1.getDb)();
        const result = db.prepare(`
      INSERT INTO live_events
        (project, session_id, event_type, file_path, line, column_pos,
         command, exit_code, duration_ms, success, metadata)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `).run(params.project, params.sessionId ?? null, params.eventType, params.filePath ?? null, params.line ?? null, params.column ?? null, params.command ?? null, params.exitCode ?? null, params.durationMs ?? null, params.success === undefined ? null : (params.success ? 1 : 0), JSON.stringify(params.metadata || {}));
        return Number(result.lastInsertRowid);
    }
    catch (e) {
        logger_1.logger.warn('recordEvent failed: ' + String(e));
        return -1;
    }
}
// ─── Typed Event Recorders (one per event type) ────────────────────────────
function recordFileSave(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'file_save',
        filePath: p.filePath, metadata,
    });
}
function recordFileCreate(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'file_create',
        filePath: p.filePath, metadata,
    });
}
function recordFileDelete(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'file_delete',
        filePath: p.filePath, metadata,
    });
}
function recordFileRename(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'file_rename',
        filePath: p.filePath,
        metadata: { ...(metadata || {}), newPath: p.newPath },
    });
}
function recordCursorMove(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'cursor_move',
        filePath: p.filePath, line: p.line, column: p.column,
        metadata: { ...(metadata || {}), selectionLength: p.selectionLength },
    });
}
function recordFileFocus(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'file_focus',
        filePath: p.filePath, metadata: { ...(metadata || {}), previousFile: p.previousFile },
    });
}
function recordFileBlur(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'file_blur',
        filePath: p.filePath, metadata,
    });
}
function recordTerminalCommand(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'terminal_command',
        command: p.command, filePath: p.cwd,
        metadata,
    });
}
function recordTerminalCommandDone(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'terminal_command_done',
        command: p.command, filePath: p.cwd,
        exitCode: p.exitCode, durationMs: p.durationMs,
        success: p.exitCode === 0,
        metadata,
    });
}
function recordTestRun(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'test_run', metadata,
    });
}
function recordTestPass(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'test_pass',
        filePath: p.testFile, command: p.testName,
        durationMs: p.durationMs, success: true,
        metadata,
    });
}
function recordTestFail(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'test_fail',
        filePath: p.testFile, command: p.testName,
        durationMs: p.durationMs, success: false,
        metadata: { ...(metadata || {}), errorMessage: p.errorMessage },
    });
}
function recordBuildStart(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'build_start',
        command: p.buildType, metadata,
    });
}
function recordBuildEnd(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'build_end',
        command: p.buildType, durationMs: p.durationMs, success: p.success,
        metadata: { ...(metadata || {}), errorCount: p.errorCount },
    });
}
function recordError(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'error',
        filePath: p.filePath, line: p.line, command: p.errorType,
        success: false,
        metadata: {
            ...(metadata || {}),
            errorMessage: p.errorMessage,
            stackTrace: p.stackTrace,
        },
    });
}
function recordGitCommit(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'git_commit',
        command: p.message,
        metadata: { ...(metadata || {}), commitHash: p.commitHash, branch: p.branch },
    });
}
function recordGitBranch(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'git_branch',
        filePath: p.toBranch, command: p.fromBranch,
        metadata: { ...(metadata || {}), reason: p.reason },
    });
}
function recordAIPrompt(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'ai_prompt',
        command: p.toolName,
        metadata: { ...(metadata || {}), prompt: p.prompt, taskType: p.taskType },
    });
}
function recordAIResponse(p, metadata) {
    let successValue = null;
    if (p.accepted === true)
        successValue = true;
    else if (p.accepted === false)
        successValue = false;
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'ai_response',
        command: p.toolName,
        durationMs: p.durationMs ?? null, success: successValue,
        metadata: { ...(metadata || {}), taskType: p.taskType },
    });
}
function recordSessionStart(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'session_start',
        command: p.toolName, metadata,
    });
}
function recordSessionEnd(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'session_end',
        command: p.toolName, metadata,
    });
}
function recordPackageChange(p, metadata) {
    return recordEvent({
        project: p.project, sessionId: p.sessionId, eventType: 'package_change',
        command: p.packageName,
        metadata: { ...(metadata || {}), oldVersion: p.oldVersion, newVersion: p.newVersion },
    });
}
function getTimeline(query) {
    ensureSchema();
    const db = (0, database_1.getDb)();
    const where = ['project = ?'];
    const args = [query.project];
    if (query.sessionId !== undefined) {
        where.push('session_id = ?');
        args.push(query.sessionId);
    }
    if (query.eventTypes && query.eventTypes.length > 0) {
        where.push(`event_type IN (${query.eventTypes.map(() => '?').join(',')})`);
        args.push(...query.eventTypes);
    }
    if (query.since) {
        where.push('created_at >= ?');
        args.push(query.since);
    }
    if (query.until) {
        where.push('created_at <= ?');
        args.push(query.until);
    }
    if (query.filePath) {
        where.push('file_path = ?');
        args.push(query.filePath);
    }
    if (query.filePattern) {
        where.push('file_path LIKE ?');
        args.push(query.filePattern);
    }
    const limit = Math.min(query.limit ?? 200, 2000);
    const sql = `
    SELECT id, project, session_id, event_type, file_path, line, column_pos,
           command, exit_code, duration_ms, success, metadata, created_at
    FROM live_events
    WHERE ${where.join(' AND ')}
    ORDER BY created_at ASC, id ASC
    LIMIT ?
  `;
    args.push(limit);
    const rows = db.prepare(sql).all(...args);
    return rows.map(mapEventRow);
}
function mapEventRow(r) {
    let meta = {};
    try {
        const raw = r.metadata;
        if (typeof raw === 'string' && raw)
            meta = JSON.parse(raw);
    }
    catch { /* ignore */ }
    return {
        id: Number(r.id),
        project: String(r.project || ''),
        sessionId: r.session_id ? Number(r.session_id) : null,
        eventType: String(r.event_type || 'file_save'),
        filePath: r.file_path ? String(r.file_path) : null,
        line: r.line ? Number(r.line) : null,
        column: r.column_pos ? Number(r.column_pos) : null,
        command: r.command ? String(r.command) : null,
        exitCode: r.exit_code !== null && r.exit_code !== undefined ? Number(r.exit_code) : null,
        durationMs: r.duration_ms !== null && r.duration_ms !== undefined ? Number(r.duration_ms) : null,
        success: r.success === null || r.success === undefined ? null : Number(r.success),
        metadata: meta,
        createdAt: String(r.created_at || ''),
    };
}
function getEventCounts(project, since) {
    ensureSchema();
    const db = (0, database_1.getDb)();
    const where = since ? 'WHERE project = ? AND created_at >= ?' : 'WHERE project = ?';
    const args = since ? [project, since] : [project];
    const rows = db.prepare(`SELECT event_type, COUNT(*) as cnt FROM live_events ${where} GROUP BY event_type`).all(...args);
    const result = {};
    for (const t of exports.ALL_EVENT_TYPES)
        result[t] = 0;
    for (const r of rows) {
        if (exports.ALL_EVENT_TYPES.includes(r.event_type)) {
            result[r.event_type] = r.cnt;
        }
    }
    return result;
}
function getLastEventForFile(project, filePath) {
    ensureSchema();
    const db = (0, database_1.getDb)();
    const row = db.prepare(`
    SELECT id, project, session_id, event_type, file_path, line, column_pos,
           command, exit_code, duration_ms, success, metadata, created_at
    FROM live_events
    WHERE project = ? AND file_path = ?
    ORDER BY id DESC LIMIT 1
  `).get(project, filePath);
    return row ? mapEventRow(row) : null;
}
function getMostRecentEvents(project, limit = 50) {
    ensureSchema();
    const db = (0, database_1.getDb)();
    const rows = db.prepare(`
    SELECT id, project, session_id, event_type, file_path, line, column_pos,
           command, exit_code, duration_ms, success, metadata, created_at
    FROM live_events
    WHERE project = ?
    ORDER BY id DESC LIMIT ?
  `).all(project, Math.min(limit, 500));
    return rows.map(mapEventRow);
}
// ─── Session ↔ Event Linkage ────────────────────────────────────────────────
function linkSessionToRecentEvents(project, sessionId, sinceSessionStart = true) {
    ensureSchema();
    const db = (0, database_1.getDb)();
    let linked = 0;
    if (sinceSessionStart) {
        // Link events that happened in the last 30 minutes to this session
        const result = db.prepare(`
      UPDATE live_events
      SET session_id = ?
      WHERE project = ?
        AND session_id IS NULL
        AND created_at >= datetime('now', '-30 minutes')
    `).run(sessionId, project);
        linked = result.changes;
    }
    else {
        const result = db.prepare(`
      UPDATE live_events
      SET session_id = ?
      WHERE project = ?
        AND session_id IS NULL
    `).run(sessionId, project);
        linked = result.changes;
    }
    return linked;
}
function unlinkSessionEvents(sessionId) {
    ensureSchema();
    const db = (0, database_1.getDb)();
    const result = db.prepare('UPDATE live_events SET session_id = NULL WHERE session_id = ?').run(sessionId);
    return result.changes;
}
//# sourceMappingURL=event-capture.js.map