"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventCompressor = void 0;
var analytics_core_1 = require("@amplitude/analytics-core");
var rrweb_packer_1 = require("@amplitude/rrweb-packer");
var DEFAULT_TIMEOUT = 2000;
var EventCompressor = /** @class */ (function () {
    function EventCompressor(eventsManager, config, deviceId, workerScript) {
        var _this = this;
        var _a;
        this.taskQueue = [];
        this.isProcessing = false;
        this.compressEvent = function (event) {
            var packedEvent = (0, rrweb_packer_1.pack)(event);
            return JSON.stringify(packedEvent);
        };
        this.addCompressedEventToManager = function (compressedEvent, sessionId) {
            if (_this.eventsManager && _this.deviceId) {
                _this.eventsManager.addEvent({
                    event: { type: 'replay', data: compressedEvent },
                    sessionId: sessionId,
                    deviceId: _this.deviceId,
                });
            }
        };
        this.addCompressedEvent = function (event, sessionId) {
            if (_this.worker) {
                // This indirectly compresses the event.
                try {
                    _this.worker.postMessage({ event: event, sessionId: sessionId });
                }
                catch (err) {
                    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
                    if (err.name === 'DataCloneError') {
                        // fallback: serialize
                        _this.worker.postMessage(JSON.stringify({ event: event, sessionId: sessionId }));
                    }
                    else {
                        _this.config.loggerProvider.warn('Unexpected error while posting message to worker:', err);
                    }
                }
            }
            else {
                var compressedEvent = _this.compressEvent(event);
                _this.addCompressedEventToManager(compressedEvent, sessionId);
            }
        };
        this.terminate = function () {
            var _a;
            (_a = _this.worker) === null || _a === void 0 ? void 0 : _a.terminate();
        };
        var globalScope = (0, analytics_core_1.getGlobalScope)();
        this.canUseIdleCallback = globalScope && 'requestIdleCallback' in globalScope;
        this.eventsManager = eventsManager;
        this.config = config;
        this.deviceId = deviceId;
        this.timeout = ((_a = config.performanceConfig) === null || _a === void 0 ? void 0 : _a.timeout) || DEFAULT_TIMEOUT;
        if (workerScript) {
            config.loggerProvider.log('Enabling web worker for compression');
            try {
                var blob = new Blob([workerScript], { type: 'application/javascript' });
                var blobUrl = URL.createObjectURL(blob);
                var worker_1 = new Worker(blobUrl);
                worker_1.onerror = function (e) {
                    e.preventDefault();
                    config.loggerProvider.error('Worker failed, falling back to non-worker compression:', e);
                    worker_1.terminate();
                    _this.worker = undefined;
                };
                worker_1.onmessage = function (e) {
                    var _a = e.data, compressedEvent = _a.compressedEvent, sessionId = _a.sessionId;
                    _this.addCompressedEventToManager(compressedEvent, sessionId);
                };
                this.worker = worker_1;
            }
            catch (error) {
                config.loggerProvider.error('Failed to create worker, falling back to non-worker compression:', error);
            }
        }
    }
    // Schedule processing during idle time
    EventCompressor.prototype.scheduleIdleProcessing = function () {
        var _this = this;
        if (!this.isProcessing) {
            this.isProcessing = true;
            requestIdleCallback(function (idleDeadline) {
                _this.processQueue(idleDeadline);
            }, { timeout: this.timeout });
        }
    };
    // Add an event to the task queue if idle callback is supported or compress the event directly
    EventCompressor.prototype.enqueueEvent = function (event, sessionId) {
        var _a;
        if (this.canUseIdleCallback && ((_a = this.config.performanceConfig) === null || _a === void 0 ? void 0 : _a.enabled)) {
            this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');
            this.taskQueue.push({ event: event, sessionId: sessionId });
            this.scheduleIdleProcessing();
        }
        else {
            this.config.loggerProvider.debug('Processing event without idle callback.');
            this.addCompressedEvent(event, sessionId);
        }
    };
    // Process the task queue during idle time
    EventCompressor.prototype.processQueue = function (idleDeadline) {
        var _this = this;
        // Process tasks while there's idle time or until the max number of tasks is reached
        while (this.taskQueue.length > 0 && (idleDeadline.timeRemaining() > 0 || idleDeadline.didTimeout)) {
            var task = this.taskQueue.shift();
            if (task) {
                var event_1 = task.event, sessionId = task.sessionId;
                this.addCompressedEvent(event_1, sessionId);
            }
        }
        // If there are still tasks in the queue, schedule the next idle callback
        if (this.taskQueue.length > 0) {
            requestIdleCallback(function (idleDeadline) {
                _this.processQueue(idleDeadline);
            }, { timeout: this.timeout });
        }
        else {
            this.isProcessing = false;
        }
    };
    return EventCompressor;
}());
exports.EventCompressor = EventCompressor;
//# sourceMappingURL=event-compressor.js.map