"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const replay_1 = require("../walls/01-context/sessions/replay");
const event_capture_1 = require("../walls/01-context/sessions/event-capture");
const database_1 = require("../walls/06-memory/database/database");
const session_memory_1 = require("../walls/01-context/sessions/session-memory");
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
describe('Cross-Memory Replay Engine (Phase 4)', () => {
    let originalHome;
    let tmpHome;
    beforeAll(() => {
        tmpHome = path.join(os.tmpdir(), 'fivo-cell-replay-' + Date.now());
        fs.mkdirSync(tmpHome, { recursive: true });
        originalHome = process.env.USERPROFILE;
        process.env.USERPROFILE = tmpHome;
        try {
            (0, database_1.closeDb)();
        }
        catch { /* ignore */ }
        (0, database_1.initializeDatabase)();
    });
    afterAll(() => {
        process.env.USERPROFILE = originalHome;
        try {
            (0, database_1.closeDb)();
        }
        catch { /* ignore */ }
        try {
            fs.rmSync(tmpHome, { recursive: true, force: true });
        }
        catch { /* ignore */ }
    });
    beforeEach(() => {
        try {
            (0, database_1.closeDb)();
        }
        catch { /* ignore */ }
        (0, database_1.initializeDatabase)();
        try {
            const db = (0, database_1.getDb)();
            db.exec('DELETE FROM live_events; DELETE FROM sessions;');
        }
        catch { /* ignore */ }
    });
    // ─── Replay basic ──────────────────────────────────────────────────────
    describe('basic replay', () => {
        it('returns empty result for project with no events', () => {
            const result = (0, replay_1.replay)({ project: 'empty', format: 'text' });
            expect(result.filteredCount).toBe(0);
            expect(result.totalEvents).toBe(0);
            expect(result.events.length).toBe(0);
        });
        it('replays all events for a project', () => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'b.ts' });
            (0, event_capture_1.recordCursorMove)({ project: 'p1', filePath: 'a.ts', line: 5, column: 0 });
            const result = (0, replay_1.replay)({ project: 'p1', format: 'text' });
            expect(result.filteredCount).toBe(3);
            expect(result.eventsByType.file_save).toBe(2);
            expect(result.eventsByType.cursor_move).toBe(1);
        });
        it('returns text formatted output', () => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            const result = (0, replay_1.replay)({ project: 'p1', format: 'text' });
            expect(result.formatted).toContain('Session Replay');
            expect(result.formatted).toContain('p1');
            expect(result.formatted).toContain('file_save');
        });
        it('returns json formatted output', () => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            const result = (0, replay_1.replay)({ project: 'p1', format: 'json' });
            const parsed = JSON.parse(result.formatted);
            expect(parsed.project).toBe('p1');
            expect(parsed.filteredCount).toBe(1);
        });
        it('returns markdown formatted output', () => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            const result = (0, replay_1.replay)({ project: 'p1', format: 'markdown' });
            expect(result.formatted).toContain('# Session Replay');
            expect(result.formatted).toContain('## Event Breakdown');
            expect(result.formatted).toContain('## Timeline');
        });
        it('returns compact formatted output', () => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            const result = (0, replay_1.replay)({ project: 'p1', format: 'compact' });
            expect(result.formatted).toContain('file_save');
            expect(result.formatted).toContain('a.ts');
        });
    });
    // ─── Filtering ────────────────────────────────────────────────────────
    describe('replay filtering', () => {
        beforeEach(() => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'b.ts' });
            (0, event_capture_1.recordCursorMove)({ project: 'p1', filePath: 'a.ts', line: 1, column: 0 });
            (0, event_capture_1.recordTerminalCommand)({ project: 'p1', command: 'npm test', cwd: '/proj' });
            (0, event_capture_1.recordTestFail)({ project: 'p1', testFile: 'a.test.ts', testName: 't1', errorMessage: 'failed' });
        });
        it('filters by single event type', () => {
            const result = (0, replay_1.replay)({ project: 'p1', eventTypes: ['cursor_move'], format: 'text' });
            expect(result.filteredCount).toBe(1);
        });
        it('filters by multiple event types', () => {
            const result = (0, replay_1.replay)({
                project: 'p1', eventTypes: ['cursor_move', 'terminal_command'], format: 'text',
            });
            expect(result.filteredCount).toBe(2);
        });
        it('filters by file path', () => {
            const result = (0, replay_1.replay)({ project: 'p1', filePath: 'a.ts', format: 'text' });
            expect(result.filteredCount).toBe(2); // save + cursor_move both on a.ts
        });
        it('filters by file pattern', () => {
            const result = (0, replay_1.replay)({ project: 'p1', filePattern: '%a.ts', format: 'text' });
            expect(result.filteredCount).toBe(2);
        });
        it('respects limit', () => {
            const result = (0, replay_1.replay)({ project: 'p1', limit: 2, format: 'text' });
            expect(result.filteredCount).toBe(2);
        });
    });
    // ─── Time span computation ────────────────────────────────────────────
    describe('time span computation', () => {
        it('computes duration from first to last event', async () => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            // Sleep 100ms
            await new Promise(r => setTimeout(r, 100));
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'b.ts' });
            const result = (0, replay_1.replay)({ project: 'p1', format: 'text' });
            expect(result.startTime).toBeTruthy();
            expect(result.endTime).toBeTruthy();
            expect(result.durationMinutes).toBeGreaterThanOrEqual(0);
        });
        it('returns 0 duration for single event', () => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            const result = (0, replay_1.replay)({ project: 'p1', format: 'text' });
            expect(result.durationMinutes).toBe(0);
        });
    });
    // ─── Grouping ─────────────────────────────────────────────────────────
    describe('grouping', () => {
        beforeEach(() => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'b.ts' });
            (0, event_capture_1.recordCursorMove)({ project: 'p1', filePath: 'a.ts', line: 1, column: 0 });
        });
        it('groups by minute', () => {
            const result = (0, replay_1.replay)({ project: 'p1', format: 'text', groupBy: 'minute' });
            expect(result.formatted).toContain('── ');
        });
        it('groups by hour', () => {
            const result = (0, replay_1.replay)({ project: 'p1', format: 'text', groupBy: 'hour' });
            expect(result.formatted).toContain('── ');
        });
        it('groups by file', () => {
            const result = (0, replay_1.replay)({ project: 'p1', format: 'text', groupBy: 'file' });
            expect(result.formatted).toContain('a.ts');
        });
        it('groups by type', () => {
            const result = (0, replay_1.replay)({ project: 'p1', format: 'text', groupBy: 'type' });
            expect(result.formatted).toContain('file_save');
            expect(result.formatted).toContain('cursor_move');
        });
    });
    // ─── Replay recent ────────────────────────────────────────────────────
    describe('replayRecent', () => {
        it('replays last N events in chronological order', () => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'b.ts' });
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'c.ts' });
            const result = (0, replay_1.replayRecent)('p1', 2, 'text');
            expect(result.filteredCount).toBe(2);
            // Last 2 events reversed to chronological = [b.ts, c.ts]
            expect(result.events[0].filePath).toBe('b.ts');
            expect(result.events[1].filePath).toBe('c.ts');
        });
    });
    // ─── Session summary ─────────────────────────────────────────────────
    describe('summarizeSession', () => {
        it('returns null for non-existent session', () => {
            const summary = (0, replay_1.summarizeSession)('p1', 999);
            expect(summary).toBeNull();
        });
        it('summarizes a complete session with all event types', () => {
            const mem = new session_memory_1.SessionMemory();
            const sessionId = mem.startSession('claude-code', 'p1');
            (0, event_capture_1.recordSessionStart)({ project: 'p1', sessionId, toolName: 'claude-code' });
            (0, event_capture_1.recordFileFocus)({ project: 'p1', sessionId, filePath: 'src/api.ts' });
            (0, event_capture_1.recordCursorMove)({ project: 'p1', sessionId, filePath: 'src/api.ts', line: 5, column: 0 });
            (0, event_capture_1.recordFileSave)({ project: 'p1', sessionId, filePath: 'src/api.ts' });
            (0, event_capture_1.recordTerminalCommand)({ project: 'p1', sessionId, command: 'npm test', cwd: '/p1' });
            (0, event_capture_1.recordTestFail)({ project: 'p1', sessionId, testFile: 'a.test.ts', testName: 't1', errorMessage: 'oops' });
            (0, event_capture_1.recordError)({ project: 'p1', sessionId, errorMessage: 'big error', errorType: 'runtime' });
            (0, event_capture_1.recordAIPrompt)({ project: 'p1', sessionId, toolName: 'claude-code', taskType: 'debug', prompt: 'fix' });
            (0, event_capture_1.recordAIResponse)({ project: 'p1', sessionId, toolName: 'claude-code', taskType: 'debug', accepted: true, durationMs: 1000 });
            (0, event_capture_1.recordBuildStart)({ project: 'p1', sessionId, buildType: 'tsc' });
            (0, event_capture_1.recordBuildEnd)({ project: 'p1', sessionId, buildType: 'tsc', durationMs: 3000, success: true });
            (0, event_capture_1.recordGitCommit)({ project: 'p1', sessionId, commitHash: 'abc', message: 'wip', branch: 'main' });
            (0, event_capture_1.recordSessionEnd)({ project: 'p1', sessionId, toolName: 'claude-code' });
            mem.endSession(sessionId, {
                filesTouched: ['src/api.ts'],
                keyDecisions: ['decided to use vitest'],
                contextSnapshot: 'debugging auth.test.ts failure',
            });
            const summary = (0, replay_1.summarizeSession)('p1', sessionId);
            expect(summary).not.toBeNull();
            expect(summary.sessionId).toBe(sessionId);
            expect(summary.toolName).toBe('claude-code');
            expect(summary.totalEvents).toBe(13);
            expect(summary.uniqueFiles).toContain('src/api.ts');
            expect(summary.uniqueCommands).toContain('npm test');
            expect(summary.testFails).toBe(1);
            expect(summary.errors).toBe(1);
            expect(summary.aiPrompts).toBe(1);
            expect(summary.aiAccepted).toBe(1);
            expect(summary.aiRejected).toBe(0);
            expect(summary.lastFileTouched).toBe('src/api.ts');
            expect(summary.lastErrorMessage).toBe('big error');
            expect(summary.contextSnapshot).toContain('debugging auth.test.ts');
        });
        it('renders session summary as text', () => {
            const mem = new session_memory_1.SessionMemory();
            const sessionId = mem.startSession('cursor', 'p1');
            (0, event_capture_1.recordFileSave)({ project: 'p1', sessionId, filePath: 'a.ts' });
            mem.endSession(sessionId, { filesTouched: ['a.ts'] });
            const summary = (0, replay_1.summarizeSession)('p1', sessionId);
            const text = (0, replay_1.renderSessionSummary)(summary);
            expect(text).toContain('Session #' + sessionId);
            expect(text).toContain('cursor');
            expect(text).toContain('Files:');
            expect(text).toContain('a.ts');
        });
    });
    // ─── Event breakdown ─────────────────────────────────────────────────
    describe('event breakdown', () => {
        it('includes all 22 event types in breakdown, with 0 for unseen', () => {
            (0, event_capture_1.recordFileSave)({ project: 'p1', filePath: 'a.ts' });
            const result = (0, replay_1.replay)({ project: 'p1', format: 'text' });
            expect(result.eventsByType.file_save).toBe(1);
            expect(result.eventsByType.cursor_move).toBe(0);
            expect(result.eventsByType.terminal_command).toBe(0);
            expect(result.eventsByType.ai_prompt).toBe(0);
            expect(result.eventsByType.session_start).toBe(0);
            // 22 event types total
            const keys = Object.keys(result.eventsByType);
            expect(keys.length).toBeGreaterThanOrEqual(22);
        });
    });
    // ─── Integration with end-to-end scenario ────────────────────────────
    describe('integration: realistic session', () => {
        it('replays a realistic 1-hour session', async () => {
            const mem = new session_memory_1.SessionMemory();
            const sessionId = mem.startSession('cursor', 'demo-project');
            (0, event_capture_1.recordSessionStart)({ project: 'demo-project', sessionId, toolName: 'cursor' });
            // User opens file
            (0, event_capture_1.recordFileFocus)({ project: 'demo-project', sessionId, filePath: 'src/auth.ts' });
            // Edits
            (0, event_capture_1.recordCursorMove)({ project: 'demo-project', sessionId, filePath: 'src/auth.ts', line: 1, column: 0 });
            (0, event_capture_1.recordFileSave)({ project: 'demo-project', sessionId, filePath: 'src/auth.ts' });
            // Switches file
            (0, event_capture_1.recordFileFocus)({ project: 'demo-project', sessionId, filePath: 'src/auth.ts', previousFile: 'src/auth.ts' });
            (0, event_capture_1.recordFileFocus)({ project: 'demo-project', sessionId, filePath: 'tests/auth.test.ts', previousFile: 'src/auth.ts' });
            // Runs tests
            (0, event_capture_1.recordTerminalCommand)({ project: 'demo-project', sessionId, command: 'npm test', cwd: '/demo' });
            (0, event_capture_1.recordTestRun)({ project: 'demo-project', sessionId });
            (0, event_capture_1.recordTestFail)({
                project: 'demo-project', sessionId,
                testFile: 'tests/auth.test.ts', testName: 'should hash',
                errorMessage: 'bcrypt not defined',
            });
            // Asks AI
            (0, event_capture_1.recordAIPrompt)({
                project: 'demo-project', sessionId, toolName: 'cursor',
                taskType: 'debug', prompt: 'how to import bcrypt?',
            });
            (0, event_capture_1.recordAIResponse)({
                project: 'demo-project', sessionId, toolName: 'cursor',
                taskType: 'debug', accepted: true, durationMs: 2300,
            });
            // Fixes it, runs again
            (0, event_capture_1.recordFileSave)({ project: 'demo-project', sessionId, filePath: 'src/auth.ts' });
            (0, event_capture_1.recordTerminalCommandDone)({
                project: 'demo-project', sessionId, command: 'npm test', cwd: '/demo',
                exitCode: 0, durationMs: 12500,
            });
            (0, event_capture_1.recordBuildStart)({ project: 'demo-project', sessionId, buildType: 'tsc' });
            (0, event_capture_1.recordBuildEnd)({
                project: 'demo-project', sessionId, buildType: 'tsc',
                durationMs: 3400, success: true,
            });
            // Commits
            (0, event_capture_1.recordGitCommit)({
                project: 'demo-project', sessionId,
                commitHash: 'abc1234', message: 'fix: bcrypt import', branch: 'main',
            });
            (0, event_capture_1.recordSessionEnd)({ project: 'demo-project', sessionId, toolName: 'cursor' });
            mem.endSession(sessionId, {
                filesTouched: ['src/auth.ts', 'tests/auth.test.ts'],
                keyDecisions: ['Use bcrypt for password hashing'],
                contextSnapshot: 'Fixed auth.test.ts bcrypt import bug',
            });
            // Replay
            const result = (0, replay_1.replay)({ project: 'demo-project', sessionId, format: 'text' });
            expect(result.filteredCount).toBe(17);
            expect(result.eventsByType.file_save).toBe(2);
            expect(result.eventsByType.cursor_move).toBe(1);
            expect(result.eventsByType.file_focus).toBe(3);
            expect(result.eventsByType.test_fail).toBe(1);
            expect(result.eventsByType.ai_prompt).toBe(1);
            expect(result.eventsByType.ai_response).toBe(1);
            expect(result.eventsByType.build_end).toBe(1);
            expect(result.eventsByType.git_commit).toBe(1);
            // Session summary
            const summary = (0, replay_1.summarizeSession)('demo-project', sessionId);
            expect(summary.testFails).toBe(1);
            expect(summary.aiPrompts).toBe(1);
            expect(summary.aiAccepted).toBe(1);
            expect(summary.lastFileTouched).toBe('src/auth.ts');
            // Replay text contains key elements
            expect(result.formatted).toContain('demo-project');
            expect(result.formatted).toContain('cursor');
            expect(result.formatted).toContain('bcrypt');
            expect(result.formatted).toContain('abc1234');
        });
    });
});
//# sourceMappingURL=cross-memory-replay.test.js.map