/**
 * Deterministic Session Replay (Item 105)
 */
import fs from 'fs-extra';
import path from 'path';
import { EventEmitter } from 'events';
import crypto from 'crypto';
export class SessionReplayManager extends EventEmitter {
    storageDir = '.codebuddy/replays';
    currentSession = null;
    recording = false;
    startRecording(name, metadata) {
        this.currentSession = {
            id: crypto.randomBytes(8).toString('hex'),
            name,
            startTime: new Date(),
            events: [],
            metadata,
        };
        this.recording = true;
        this.emit('recording-started', this.currentSession.id);
        return this.currentSession;
    }
    stopRecording() {
        if (!this.currentSession)
            return null;
        this.currentSession.endTime = new Date();
        this.recording = false;
        const session = this.currentSession;
        this.emit('recording-stopped', session.id);
        return session;
    }
    recordEvent(type, data) {
        if (!this.recording || !this.currentSession)
            return;
        const event = {
            id: crypto.randomBytes(4).toString('hex'),
            timestamp: Date.now(),
            type,
            data,
            hash: crypto.createHash('sha256').update(JSON.stringify(data)).digest('hex').slice(0, 8),
        };
        this.currentSession.events.push(event);
        this.emit('event-recorded', event);
    }
    async saveSession(session) {
        await fs.ensureDir(this.storageDir);
        const safeName = session.name.replace(/[^a-z0-9]/gi, '-');
        const filename = session.id + '-' + safeName + '.json';
        const filePath = path.join(this.storageDir, filename);
        await fs.writeJson(filePath, session, { spaces: 2 });
        return filePath;
    }
    async loadSession(sessionId) {
        if (!await fs.pathExists(this.storageDir))
            return null;
        const files = await fs.readdir(this.storageDir);
        const sessionFile = files.find(f => f.startsWith(sessionId));
        if (!sessionFile)
            return null;
        return fs.readJson(path.join(this.storageDir, sessionFile));
    }
    async listSessions() {
        if (!await fs.pathExists(this.storageDir))
            return [];
        const files = await fs.readdir(this.storageDir);
        const sessions = [];
        for (const file of files) {
            if (file.endsWith('.json')) {
                try {
                    const session = await fs.readJson(path.join(this.storageDir, file));
                    sessions.push({ id: session.id, name: session.name, date: new Date(session.startTime) });
                }
                catch { /* skip */ }
            }
        }
        return sessions.sort((a, b) => b.date.getTime() - a.date.getTime());
    }
    async replay(sessionId, options = {}) {
        const session = await this.loadSession(sessionId);
        if (!session)
            throw new Error('Session not found');
        const speed = options.speed || 1;
        this.emit('replay-started', sessionId);
        let lastTs = session.events[0]?.timestamp || 0;
        for (const event of session.events) {
            const delay = (event.timestamp - lastTs) / speed;
            if (delay > 0)
                await new Promise(r => setTimeout(r, Math.min(delay, 1000)));
            if (options.onEvent)
                options.onEvent(event);
            this.emit('replay-event', event);
            lastTs = event.timestamp;
        }
        this.emit('replay-completed', sessionId);
    }
    verifyIntegrity(session) {
        for (const event of session.events) {
            const expected = crypto.createHash('sha256').update(JSON.stringify(event.data)).digest('hex').slice(0, 8);
            if (event.hash !== expected)
                return false;
        }
        return true;
    }
    isRecording() { return this.recording; }
    getCurrentSession() { return this.currentSession; }
}
let instance = null;
export function getSessionReplayManager() {
    if (!instance)
        instance = new SessionReplayManager();
    return instance;
}
export default SessionReplayManager;
//# sourceMappingURL=session-replay.js.map