"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSessionReplayJoinedConfigGenerator = exports.SessionReplayJoinedConfigGenerator = exports.removeInvalidSelectorsFromPrivacyConfig = void 0;
var tslib_1 = require("tslib");
var analytics_core_1 = require("@amplitude/analytics-core");
var helpers_1 = require("../helpers");
var local_config_1 = require("./local-config");
var removeInvalidSelectorsFromPrivacyConfig = function (privacyConfig, loggerProvider) {
    // This allows us to not search the DOM.
    var fragment = document.createDocumentFragment();
    var dropInvalidSelectors = function (selectors) {
        if (selectors === void 0) { selectors = []; }
        if (typeof selectors === 'string') {
            selectors = [selectors];
        }
        selectors = selectors.filter(function (selector) {
            try {
                fragment.querySelector(selector);
            }
            catch (_a) {
                loggerProvider.warn("[session-replay-browser] omitting selector \"".concat(selector, "\" because it is invalid"));
                return false;
            }
            return true;
        });
        if (selectors.length === 0) {
            return undefined;
        }
        return selectors;
    };
    privacyConfig.blockSelector = dropInvalidSelectors(privacyConfig.blockSelector);
    privacyConfig.maskSelector = dropInvalidSelectors(privacyConfig.maskSelector);
    privacyConfig.unmaskSelector = dropInvalidSelectors(privacyConfig.unmaskSelector);
    return privacyConfig;
};
exports.removeInvalidSelectorsFromPrivacyConfig = removeInvalidSelectorsFromPrivacyConfig;
var SessionReplayJoinedConfigGenerator = /** @class */ (function () {
    function SessionReplayJoinedConfigGenerator(remoteConfigClient, localConfig) {
        this.localConfig = localConfig;
        this.remoteConfigClient = remoteConfigClient;
    }
    SessionReplayJoinedConfigGenerator.prototype.generateJoinedConfig = function () {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var config, sessionReplayRemoteConfig, samplingConfig, remotePrivacyConfig, targetingConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _d, _e, _f, selector, selectorType;
            var e_1, _g;
            var _this = this;
            return tslib_1.__generator(this, function (_h) {
                switch (_h.label) {
                    case 0:
                        config = tslib_1.__assign({}, this.localConfig);
                        // Special case here as optOut is implemented via getter/setter
                        config.optOut = this.localConfig.optOut;
                        // We always want captureEnabled to be true, unless there's an override
                        // in the remote config.
                        config.captureEnabled = true;
                        // Subscribe to remote config client to get the config (uses cache if available)
                        return [4 /*yield*/, new Promise(function (resolve) {
                                _this.remoteConfigClient.subscribe('configs.sessionReplay', 'all', function (remoteConfig, source) {
                                    var _a;
                                    _this.localConfig.loggerProvider.debug("Session Replay remote configuration received from ".concat(source, ":"), JSON.stringify(remoteConfig, null, 2));
                                    if (remoteConfig) {
                                        // remoteConfig is already filtered to 'configs.sessionReplay' namespace
                                        var namespaceConfig = remoteConfig;
                                        var samplingConfig_1 = namespaceConfig.sr_sampling_config;
                                        var privacyConfig = namespaceConfig.sr_privacy_config;
                                        var targetingConfig_1 = namespaceConfig.sr_targeting_config;
                                        var ugcFilterRules = (_a = config.interactionConfig) === null || _a === void 0 ? void 0 : _a.ugcFilterRules;
                                        // This is intentionally forced to only be set through the remote config.
                                        config.interactionConfig = namespaceConfig.sr_interaction_config;
                                        if (config.interactionConfig && ugcFilterRules) {
                                            config.interactionConfig.ugcFilterRules = ugcFilterRules;
                                        }
                                        // This is intentionally forced to only be set through the remote config.
                                        config.loggingConfig = namespaceConfig.sr_logging_config;
                                        if (samplingConfig_1 || privacyConfig || targetingConfig_1) {
                                            sessionReplayRemoteConfig = {};
                                            if (samplingConfig_1) {
                                                sessionReplayRemoteConfig.sr_sampling_config = samplingConfig_1;
                                            }
                                            if (privacyConfig) {
                                                sessionReplayRemoteConfig.sr_privacy_config = privacyConfig;
                                            }
                                            if (targetingConfig_1) {
                                                sessionReplayRemoteConfig.sr_targeting_config = targetingConfig_1;
                                            }
                                        }
                                    }
                                    // Resolve on first callback
                                    resolve();
                                });
                            })];
                    case 1:
                        // Subscribe to remote config client to get the config (uses cache if available)
                        _h.sent();
                        if (!sessionReplayRemoteConfig) {
                            return [2 /*return*/, {
                                    localConfig: this.localConfig,
                                    joinedConfig: config,
                                    remoteConfig: sessionReplayRemoteConfig,
                                }];
                        }
                        samplingConfig = sessionReplayRemoteConfig.sr_sampling_config, remotePrivacyConfig = sessionReplayRemoteConfig.sr_privacy_config, targetingConfig = sessionReplayRemoteConfig.sr_targeting_config;
                        if (samplingConfig && Object.keys(samplingConfig).length > 0) {
                            if (Object.prototype.hasOwnProperty.call(samplingConfig, 'capture_enabled')) {
                                config.captureEnabled = samplingConfig.capture_enabled;
                            }
                            else {
                                config.captureEnabled = false;
                            }
                            if (Object.prototype.hasOwnProperty.call(samplingConfig, 'sample_rate')) {
                                config.sampleRate = samplingConfig.sample_rate;
                            }
                        }
                        else {
                            // If config API response was valid (ie 200), but no config returned, assume that
                            // customer has not yet set up config, and use sample rate from SDK options,
                            // allowing for immediate replay capture
                            config.captureEnabled = true;
                            this.localConfig.loggerProvider.debug('Remote config successfully fetched, but no values set for project, Session Replay capture enabled.');
                        }
                        // Remote config join acts somewhat like a left join between the remote and the local
                        // config. That is, remote config has precedence over local values as with sampling.
                        // However, non conflicting values will be added to the lists.
                        // Here's an example to illustrate:
                        //
                        // Remote config:   {'.selector1': 'MASK',   '.selector2': 'UNMASK'}
                        // Local config:    {'.selector1': 'UNMASK',                         '.selector3': 'MASK'}
                        //
                        // Resolved config: {'.selector1': 'MASK',   '.selector2': 'UNMASK', '.selector3': 'MASK'}
                        // config.privacyConfig = {
                        //   ...(config.privacyConfig ?? {}),
                        //   ...remotePrivacyConfig,
                        // };
                        if (remotePrivacyConfig) {
                            localPrivacyConfig = (_a = config.privacyConfig) !== null && _a !== void 0 ? _a : {};
                            joinedPrivacyConfig = {
                                defaultMaskLevel: (_c = (_b = remotePrivacyConfig.defaultMaskLevel) !== null && _b !== void 0 ? _b : localPrivacyConfig.defaultMaskLevel) !== null && _c !== void 0 ? _c : 'medium',
                                blockSelector: [],
                                maskSelector: [],
                                unmaskSelector: [],
                            };
                            privacyConfigSelectorMap = function (privacyConfig) {
                                var e_2, _a, e_3, _b, e_4, _c;
                                var _d, _e, _f;
                                var selectorMap = {};
                                if (typeof privacyConfig.blockSelector === 'string') {
                                    privacyConfig.blockSelector = [privacyConfig.blockSelector];
                                }
                                try {
                                    for (var _g = tslib_1.__values((_d = privacyConfig.blockSelector) !== null && _d !== void 0 ? _d : []), _h = _g.next(); !_h.done; _h = _g.next()) {
                                        var selector = _h.value;
                                        selectorMap[selector] = 'block';
                                    }
                                }
                                catch (e_2_1) { e_2 = { error: e_2_1 }; }
                                finally {
                                    try {
                                        if (_h && !_h.done && (_a = _g.return)) _a.call(_g);
                                    }
                                    finally { if (e_2) throw e_2.error; }
                                }
                                try {
                                    for (var _j = tslib_1.__values((_e = privacyConfig.maskSelector) !== null && _e !== void 0 ? _e : []), _k = _j.next(); !_k.done; _k = _j.next()) {
                                        var selector = _k.value;
                                        selectorMap[selector] = 'mask';
                                    }
                                }
                                catch (e_3_1) { e_3 = { error: e_3_1 }; }
                                finally {
                                    try {
                                        if (_k && !_k.done && (_b = _j.return)) _b.call(_j);
                                    }
                                    finally { if (e_3) throw e_3.error; }
                                }
                                try {
                                    for (var _l = tslib_1.__values((_f = privacyConfig.unmaskSelector) !== null && _f !== void 0 ? _f : []), _m = _l.next(); !_m.done; _m = _l.next()) {
                                        var selector = _m.value;
                                        selectorMap[selector] = 'unmask';
                                    }
                                }
                                catch (e_4_1) { e_4 = { error: e_4_1 }; }
                                finally {
                                    try {
                                        if (_m && !_m.done && (_c = _l.return)) _c.call(_l);
                                    }
                                    finally { if (e_4) throw e_4.error; }
                                }
                                return selectorMap;
                            };
                            selectorMap = tslib_1.__assign(tslib_1.__assign({}, privacyConfigSelectorMap(localPrivacyConfig)), privacyConfigSelectorMap(remotePrivacyConfig));
                            try {
                                for (_d = tslib_1.__values(Object.entries(selectorMap)), _e = _d.next(); !_e.done; _e = _d.next()) {
                                    _f = tslib_1.__read(_e.value, 2), selector = _f[0], selectorType = _f[1];
                                    if (selectorType === 'mask') {
                                        joinedPrivacyConfig.maskSelector.push(selector);
                                    }
                                    else if (selectorType === 'block') {
                                        joinedPrivacyConfig.blockSelector.push(selector);
                                    }
                                    else if (selectorType === 'unmask') {
                                        joinedPrivacyConfig.unmaskSelector.push(selector);
                                    }
                                }
                            }
                            catch (e_1_1) { e_1 = { error: e_1_1 }; }
                            finally {
                                try {
                                    if (_e && !_e.done && (_g = _d.return)) _g.call(_d);
                                }
                                finally { if (e_1) throw e_1.error; }
                            }
                            config.privacyConfig = (0, exports.removeInvalidSelectorsFromPrivacyConfig)(joinedPrivacyConfig, this.localConfig.loggerProvider);
                        }
                        if (targetingConfig && Object.keys(targetingConfig).length > 0) {
                            config.targetingConfig = targetingConfig;
                        }
                        this.localConfig.loggerProvider.debug(JSON.stringify({ name: 'session replay joined config', config: (0, helpers_1.getDebugConfig)(config) }, null, 2));
                        return [2 /*return*/, {
                                localConfig: this.localConfig,
                                joinedConfig: config,
                                remoteConfig: sessionReplayRemoteConfig,
                            }];
                }
            });
        });
    };
    return SessionReplayJoinedConfigGenerator;
}());
exports.SessionReplayJoinedConfigGenerator = SessionReplayJoinedConfigGenerator;
var createSessionReplayJoinedConfigGenerator = function (apiKey, options) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var localConfig, remoteConfigClient;
    return tslib_1.__generator(this, function (_a) {
        localConfig = new local_config_1.SessionReplayLocalConfig(apiKey, options);
        remoteConfigClient = new analytics_core_1.RemoteConfigClient(apiKey, localConfig.loggerProvider, localConfig.serverZone, options.configServerUrl);
        return [2 /*return*/, new SessionReplayJoinedConfigGenerator(remoteConfigClient, localConfig)];
    });
}); };
exports.createSessionReplayJoinedConfigGenerator = createSessionReplayJoinedConfigGenerator;
//# sourceMappingURL=joined-config.js.map