import { __assign, __awaiter, __generator, __read, __values } from "tslib";
import { createRemoteConfigFetch } from '@amplitude/analytics-remote-config';
import { getDebugConfig } from '../helpers';
import { SessionReplayLocalConfig } from './local-config';
export 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;
};
var SessionReplayJoinedConfigGenerator = /** @class */ (function () {
    function SessionReplayJoinedConfigGenerator(remoteConfigFetch, localConfig) {
        this.localConfig = localConfig;
        this.remoteConfigFetch = remoteConfigFetch;
    }
    SessionReplayJoinedConfigGenerator.prototype.generateJoinedConfig = function (sessionId) {
        var _a, _b, _c;
        return __awaiter(this, void 0, void 0, function () {
            var config, remoteConfig, samplingConfig_1, privacyConfig, _d, _e, err_1, knownError, samplingConfig, remotePrivacyConfig, localPrivacyConfig, joinedPrivacyConfig, privacyConfigSelectorMap, selectorMap, _f, _g, _h, selector, selectorType;
            var e_1, _j;
            return __generator(this, function (_k) {
                switch (_k.label) {
                    case 0:
                        config = __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;
                        _k.label = 1;
                    case 1:
                        _k.trys.push([1, 6, , 7]);
                        return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_sampling_config', sessionId)];
                    case 2:
                        samplingConfig_1 = _k.sent();
                        return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_privacy_config', sessionId)];
                    case 3:
                        privacyConfig = _k.sent();
                        // This is intentionally forced to only be set through the remote config.
                        _d = config;
                        return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_interaction_config', sessionId)];
                    case 4:
                        // This is intentionally forced to only be set through the remote config.
                        _d.interactionConfig = _k.sent();
                        // This is intentionally forced to only be set through the remote config.
                        _e = config;
                        return [4 /*yield*/, this.remoteConfigFetch.getRemoteConfig('sessionReplay', 'sr_logging_config', sessionId)];
                    case 5:
                        // This is intentionally forced to only be set through the remote config.
                        _e.loggingConfig = _k.sent();
                        if (samplingConfig_1 || privacyConfig) {
                            remoteConfig = {};
                            if (samplingConfig_1) {
                                remoteConfig.sr_sampling_config = samplingConfig_1;
                            }
                            if (privacyConfig) {
                                remoteConfig.sr_privacy_config = privacyConfig;
                            }
                        }
                        return [3 /*break*/, 7];
                    case 6:
                        err_1 = _k.sent();
                        knownError = err_1;
                        this.localConfig.loggerProvider.warn(knownError.message);
                        config.captureEnabled = false;
                        return [3 /*break*/, 7];
                    case 7:
                        if (!remoteConfig) {
                            return [2 /*return*/, config];
                        }
                        samplingConfig = remoteConfig.sr_sampling_config, remotePrivacyConfig = remoteConfig.sr_privacy_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 = __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 = __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 = __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 = __assign(__assign({}, privacyConfigSelectorMap(localPrivacyConfig)), privacyConfigSelectorMap(remotePrivacyConfig));
                            try {
                                for (_f = __values(Object.entries(selectorMap)), _g = _f.next(); !_g.done; _g = _f.next()) {
                                    _h = __read(_g.value, 2), selector = _h[0], selectorType = _h[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 (_g && !_g.done && (_j = _f.return)) _j.call(_f);
                                }
                                finally { if (e_1) throw e_1.error; }
                            }
                            config.privacyConfig = removeInvalidSelectorsFromPrivacyConfig(joinedPrivacyConfig, this.localConfig.loggerProvider);
                        }
                        this.localConfig.loggerProvider.debug(JSON.stringify({ name: 'session replay joined config', config: getDebugConfig(config) }, null, 2));
                        return [2 /*return*/, config];
                }
            });
        });
    };
    return SessionReplayJoinedConfigGenerator;
}());
export { SessionReplayJoinedConfigGenerator };
export var createSessionReplayJoinedConfigGenerator = function (apiKey, options) { return __awaiter(void 0, void 0, void 0, function () {
    var localConfig, remoteConfigFetch;
    return __generator(this, function (_a) {
        switch (_a.label) {
            case 0:
                localConfig = new SessionReplayLocalConfig(apiKey, options);
                return [4 /*yield*/, createRemoteConfigFetch({
                        localConfig: localConfig,
                        configKeys: ['sessionReplay'],
                    })];
            case 1:
                remoteConfigFetch = _a.sent();
                return [2 /*return*/, new SessionReplayJoinedConfigGenerator(remoteConfigFetch, localConfig)];
        }
    });
}); };
//# sourceMappingURL=joined-config.js.map