var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
import { logger } from '../../utils/logger';
import { isBoolean, isNullish, isNumber, isObject, isUndefined } from '../../utils/type-utils';
import { WEB_VITALS_ALLOWED_METRICS, WEB_VITALS_ENABLED_SERVER_SIDE } from '../../constants';
import { assignableWindow, window } from '../../utils/globals';
import Config from '../../config';
export var FLUSH_TO_CAPTURE_TIMEOUT_MILLISECONDS = 8000;
var ONE_MINUTE_IN_MILLIS = 60 * 1000;
export var FIFTEEN_MINUTES_IN_MILLIS = 15 * ONE_MINUTE_IN_MILLIS;
var LOGGER_PREFIX = '[Web Vitals]';
var WebVitalsAutocapture = /** @class */ (function () {
    function WebVitalsAutocapture(instance) {
        var _this = this;
        var _a;
        this.instance = instance;
        this._enabledServerSide = false;
        this._initialized = false;
        this.buffer = { url: undefined, metrics: [], firstMetricTimestamp: undefined };
        this._flushToCapture = function () {
            clearTimeout(_this._delayedFlushTimer);
            if (_this.buffer.metrics.length === 0) {
                return;
            }
            _this.instance.capture('$web_vitals', _this.buffer.metrics.reduce(function (acc, metric) {
                var _a;
                return (__assign(__assign({}, acc), (_a = {}, _a["$web_vitals_".concat(metric.name, "_event")] = __assign({}, metric), _a["$web_vitals_".concat(metric.name, "_value")] = metric.value, _a)));
            }, {}));
            _this.buffer = { url: undefined, metrics: [], firstMetricTimestamp: undefined };
        };
        this._addToBuffer = function (metric) {
            var _a;
            var sessionIds = (_a = _this.instance.sessionManager) === null || _a === void 0 ? void 0 : _a.checkAndGetSessionAndWindowId(true);
            if (isUndefined(sessionIds)) {
                logger.error(LOGGER_PREFIX + 'Could not read session ID. Dropping metrics!');
                return;
            }
            _this.buffer = _this.buffer || { url: undefined, metrics: [], firstMetricTimestamp: undefined };
            var $currentUrl = _this._currentURL();
            if (isUndefined($currentUrl)) {
                return;
            }
            if (isNullish(metric === null || metric === void 0 ? void 0 : metric.name) || isNullish(metric === null || metric === void 0 ? void 0 : metric.value)) {
                logger.error(LOGGER_PREFIX + 'Invalid metric received', metric);
                return;
            }
            // we observe some very large values sometimes, we'll ignore them
            // since the likelihood of LCP > 1 hour being correct is very low
            if (_this._maxAllowedValue && metric.value >= _this._maxAllowedValue) {
                logger.error(LOGGER_PREFIX + 'Ignoring metric with value >= ' + _this._maxAllowedValue, metric);
                return;
            }
            var urlHasChanged = _this.buffer.url !== $currentUrl;
            if (urlHasChanged) {
                // we need to send what we have
                _this._flushToCapture();
                // poor performance is >4s, we wait twice that time to send
                // this is in case we haven't received all metrics
                // we'll at least gather some
                _this._delayedFlushTimer = setTimeout(_this._flushToCapture, FLUSH_TO_CAPTURE_TIMEOUT_MILLISECONDS);
            }
            if (isUndefined(_this.buffer.url)) {
                _this.buffer.url = $currentUrl;
            }
            _this.buffer.firstMetricTimestamp = isUndefined(_this.buffer.firstMetricTimestamp)
                ? Date.now()
                : _this.buffer.firstMetricTimestamp;
            _this.buffer.metrics.push(__assign(__assign({}, metric), { $current_url: $currentUrl, $session_id: sessionIds.sessionId, $window_id: sessionIds.windowId, timestamp: Date.now() }));
            if (_this.buffer.metrics.length === _this.allowedMetrics.length) {
                // we have all allowed metrics
                _this._flushToCapture();
            }
        };
        this._startCapturing = function () {
            var _a;
            var onLCP;
            var onCLS;
            var onFCP;
            var onINP;
            var posthogExtensions = assignableWindow.__PosthogExtensions__;
            if (!isUndefined(posthogExtensions) && !isUndefined(posthogExtensions.postHogWebVitalsCallbacks)) {
                ;
                (_a = posthogExtensions.postHogWebVitalsCallbacks, onLCP = _a.onLCP, onCLS = _a.onCLS, onFCP = _a.onFCP, onINP = _a.onINP);
            }
            if (!onLCP || !onCLS || !onFCP || !onINP) {
                logger.error(LOGGER_PREFIX + 'web vitals callbacks not loaded - not starting');
                return;
            }
            // register performance observers
            if (_this.allowedMetrics.indexOf('LCP') > -1) {
                onLCP(_this._addToBuffer.bind(_this));
            }
            if (_this.allowedMetrics.indexOf('CLS') > -1) {
                onCLS(_this._addToBuffer.bind(_this));
            }
            if (_this.allowedMetrics.indexOf('FCP') > -1) {
                onFCP(_this._addToBuffer.bind(_this));
            }
            if (_this.allowedMetrics.indexOf('INP') > -1) {
                onINP(_this._addToBuffer.bind(_this));
            }
            _this._initialized = true;
        };
        this._enabledServerSide = !!((_a = this.instance.persistence) === null || _a === void 0 ? void 0 : _a.props[WEB_VITALS_ENABLED_SERVER_SIDE]);
        this.startIfEnabled();
    }
    Object.defineProperty(WebVitalsAutocapture.prototype, "allowedMetrics", {
        get: function () {
            var _a, _b;
            var clientConfigMetricAllowList = isObject(this.instance.config.capture_performance)
                ? (_a = this.instance.config.capture_performance) === null || _a === void 0 ? void 0 : _a.web_vitals_allowed_metrics
                : undefined;
            return !isUndefined(clientConfigMetricAllowList)
                ? clientConfigMetricAllowList
                : ((_b = this.instance.persistence) === null || _b === void 0 ? void 0 : _b.props[WEB_VITALS_ALLOWED_METRICS]) || ['CLS', 'FCP', 'INP', 'LCP'];
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(WebVitalsAutocapture.prototype, "_maxAllowedValue", {
        get: function () {
            var configured = isObject(this.instance.config.capture_performance) &&
                isNumber(this.instance.config.capture_performance.__web_vitals_max_value)
                ? this.instance.config.capture_performance.__web_vitals_max_value
                : FIFTEEN_MINUTES_IN_MILLIS;
            // you can set to 0 to disable the check or any value over ten seconds
            // 1 milli to 1 minute will be set to 15 minutes, cos that would be a silly low maximum
            return 0 < configured && configured <= ONE_MINUTE_IN_MILLIS ? FIFTEEN_MINUTES_IN_MILLIS : configured;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(WebVitalsAutocapture.prototype, "isEnabled", {
        get: function () {
            var clientConfig = isObject(this.instance.config.capture_performance)
                ? this.instance.config.capture_performance.web_vitals
                : undefined;
            return isBoolean(clientConfig) ? clientConfig : this._enabledServerSide;
        },
        enumerable: false,
        configurable: true
    });
    WebVitalsAutocapture.prototype.startIfEnabled = function () {
        if (this.isEnabled && !this._initialized) {
            logger.info(LOGGER_PREFIX + ' enabled, starting...');
            this.loadScript(this._startCapturing);
        }
    };
    WebVitalsAutocapture.prototype.afterDecideResponse = function (response) {
        var _a, _b;
        var webVitalsOptIn = isObject(response.capturePerformance) && !!response.capturePerformance.web_vitals;
        var allowedMetrics = isObject(response.capturePerformance)
            ? response.capturePerformance.web_vitals_allowed_metrics
            : undefined;
        if (this.instance.persistence) {
            this.instance.persistence.register((_a = {},
                _a[WEB_VITALS_ENABLED_SERVER_SIDE] = webVitalsOptIn,
                _a));
            this.instance.persistence.register((_b = {},
                _b[WEB_VITALS_ALLOWED_METRICS] = allowedMetrics,
                _b));
        }
        // store this in-memory in case persistence is disabled
        this._enabledServerSide = webVitalsOptIn;
        this.startIfEnabled();
    };
    WebVitalsAutocapture.prototype.loadScript = function (cb) {
        var _a;
        if ((_a = assignableWindow.__PosthogExtensions__) === null || _a === void 0 ? void 0 : _a.postHogWebVitalsCallbacks) {
            // already loaded
            cb();
        }
        this.instance.requestRouter.loadScript("/static/web-vitals.js?v=".concat(Config.LIB_VERSION), function (err) {
            if (err) {
                logger.error(LOGGER_PREFIX + ' failed to load script', err);
                return;
            }
            cb();
        });
    };
    WebVitalsAutocapture.prototype._currentURL = function () {
        // TODO you should be able to mask the URL here
        var href = window ? window.location.href : undefined;
        if (!href) {
            logger.error(LOGGER_PREFIX + 'Could not determine current URL');
        }
        return href;
    };
    return WebVitalsAutocapture;
}());
export { WebVitalsAutocapture };
//# sourceMappingURL=index.js.map