import { pack } from '@rrweb/packer';
import { EventType } from '@rrweb/types';
import { record } from 'rrweb';
import { SessionType } from '@multiplayer-app/session-recorder-common';
import { getRecordConsolePlugin } from '@rrweb/rrweb-plugin-console-record';
import { isConsoleEvent } from '../utils';
import { CONTINUOUS_DEBUGGING_TIMEOUT } from '../config';
export class RecorderBrowserSDK {
    constructor() {
        this.intervals = {
            restart: null,
            bufferSnapshot: null,
        };
        this.startedAt = '';
        this.stoppedAt = '';
    }
    /**
     * Full snapshot.
     */
    takeFullSnapshot() {
        if (!this.stopFn) {
            return;
        }
        record.takeFullSnapshot();
    }
    /**
     * Initializes the recorder SDK.
     * @param config - Configuration settings.
     * @param socketService - Optional socket service.
     */
    init(config, socketService) {
        this.config = config;
        this.socketService = socketService;
    }
    /**
     * Starts recording.
     * @param sessionId - Session ID or null for buffer-only mode.
     * @param sessionType - Session type.
     */
    start(sessionId, sessionType) {
        if (!this.config) {
            throw new Error('Configuration not initialized. Call init() before start().');
        }
        this.startedAt = new Date().toISOString();
        this.stopFn = record({
            ...this._buildRecordOptions(),
            emit: async (event) => {
                const ts = event.timestamp;
                if (!sessionId) {
                    await this._handleBufferOnlyEvent(event, ts);
                    return;
                }
                this._handleLiveSessionEvent(event, ts, sessionId, sessionType);
            },
        });
        this.takeFullSnapshot();
        this._setupPeriodicSnapshots(sessionId, sessionType);
    }
    /**
     * Restarts recording. Never throws - library mode constraint.
     */
    async restart(sessionId, sessionType) {
        var _a;
        try {
            (_a = this.stopFn) === null || _a === void 0 ? void 0 : _a.call(this);
            this.start(sessionId, sessionType);
        }
        catch (_e) {
            // Silent failure
        }
    }
    /**
     * Stops recording and cleans up resources.
     */
    stop() {
        var _a, _b, _c;
        (_a = this.stopFn) === null || _a === void 0 ? void 0 : _a.call(this);
        this.stopFn = undefined;
        if (!((_b = this.config) === null || _b === void 0 ? void 0 : _b.useWebsocket)) {
            (_c = this.socketService) === null || _c === void 0 ? void 0 : _c.close();
        }
        this._clearAllIntervals();
    }
    _clearAllIntervals() {
        if (this.intervals.restart) {
            clearInterval(this.intervals.restart);
            this.intervals.restart = null;
        }
        if (this.intervals.bufferSnapshot) {
            clearInterval(this.intervals.bufferSnapshot);
            this.intervals.bufferSnapshot = null;
        }
    }
    /**
     * Sets the crash buffer.
     * @param crashBuffer - Crash buffer service.
     */
    setCrashBuffer(crashBuffer) {
        this.crashBuffer = crashBuffer;
    }
    /**
     * Mutates event in-place for performance.
     */
    _applyConsoleMasking(event) {
        var _a, _b;
        const maskFn = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.masking) === null || _b === void 0 ? void 0 : _b.maskConsoleEvent;
        if (typeof maskFn === 'function' && isConsoleEvent(event)) {
            const pluginEvt = event;
            const maskedPayload = maskFn(pluginEvt.data.payload);
            pluginEvt.data = { ...pluginEvt.data, payload: maskedPayload };
        }
    }
    /**
     * Handles buffer-only event.
     * @param event - Event.
     * @param ts - Timestamp.
     */
    async _handleBufferOnlyEvent(event, ts) {
        if (!this.crashBuffer)
            return;
        try {
            this._applyConsoleMasking(event);
            const packedEvent = pack(event);
            this.stoppedAt = new Date(ts).toISOString();
            await this.crashBuffer.appendEvent({
                ts,
                isFullSnapshot: event.type === EventType.FullSnapshot,
                event: {
                    event: packedEvent,
                    eventType: event.type,
                    timestamp: ts,
                },
            });
        }
        catch (error) {
            // Silent failure - library constraint
        }
    }
    /**
     * Handles live session event.
     * @param event - Event.
     * @param ts - Timestamp.
     * @param sessionId - Session ID.
     * @param sessionType - Session type.
     */
    _handleLiveSessionEvent(event, ts, sessionId, sessionType) {
        if (!this.socketService)
            return;
        this._applyConsoleMasking(event);
        const packedEvent = pack(event);
        this.stoppedAt = new Date(ts).toISOString();
        this.socketService.send({
            event: packedEvent,
            eventType: event.type,
            timestamp: ts,
            debugSessionId: sessionId,
            debugSessionType: sessionType,
        });
    }
    /**
     * Builds record options.
     */
    _buildRecordOptions() {
        var _a, _b, _c, _d, _f;
        const maskingConfig = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.masking) || {};
        const options = {
            maskAllInputs: (_b = maskingConfig.maskAllInputs) !== null && _b !== void 0 ? _b : true,
            sampling: { canvas: 5 },
            recordCanvas: (_c = this.config) === null || _c === void 0 ? void 0 : _c.recordCanvas,
            dataURLOptions: { type: 'image/webp', quality: 0.1 },
            inlineImages: (_d = this.config) === null || _d === void 0 ? void 0 : _d.inlineImages,
            inlineStylesheet: (_f = this.config) === null || _f === void 0 ? void 0 : _f.inlineStylesheet,
            plugins: [getRecordConsolePlugin({ level: ['log', 'error'] })],
        };
        if (maskingConfig.maskInputOptions) {
            options.maskInputOptions = maskingConfig.maskInputOptions;
        }
        if (maskingConfig.maskTextClass) {
            options.maskTextClass = maskingConfig.maskTextClass;
        }
        if (maskingConfig.maskTextSelector) {
            options.maskTextSelector = maskingConfig.maskTextSelector;
        }
        if (typeof maskingConfig.maskInput === 'function') {
            options.maskInputFn = maskingConfig.maskInput;
        }
        if (typeof maskingConfig.maskText === 'function') {
            options.maskTextFn = maskingConfig.maskText;
        }
        return options;
    }
    /**
     * Sets up periodic snapshots.
     * @param sessionId - Session ID.
     * @param sessionType - Session type.
     */
    _setupPeriodicSnapshots(sessionId, sessionType) {
        var _a, _b;
        this._clearAllIntervals();
        if (sessionType === SessionType.CONTINUOUS) {
            this.intervals.restart = setInterval(() => {
                this.takeFullSnapshot();
            }, CONTINUOUS_DEBUGGING_TIMEOUT);
        }
        if (!sessionId && ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.buffering) === null || _b === void 0 ? void 0 : _b.enabled)) {
            const interval = this.config.buffering.snapshotIntervalMs || 20000;
            this.intervals.bufferSnapshot = setInterval(() => {
                this.takeFullSnapshot();
            }, interval);
        }
    }
}
//# sourceMappingURL=index.js.map