import { SURVEYS } from './constants';
import { getSurveySeenStorageKeys } from './extensions/surveys/surveys-utils';
import { SurveyQuestionBranchingType, SurveyQuestionType, } from './posthog-surveys-types';
import { assignableWindow, document, window } from './utils/globals';
import { createLogger } from './utils/logger';
import { isUrlMatchingRegex } from './utils/request-utils';
import { SurveyEventReceiver } from './utils/survey-event-receiver';
import { isNullish } from './utils/type-utils';
var logger = createLogger('[Surveys]');
export var surveyUrlValidationMap = {
    icontains: function (conditionsUrl) {
        return !!window && window.location.href.toLowerCase().indexOf(conditionsUrl.toLowerCase()) > -1;
    },
    not_icontains: function (conditionsUrl) {
        return !!window && window.location.href.toLowerCase().indexOf(conditionsUrl.toLowerCase()) === -1;
    },
    regex: function (conditionsUrl) { return !!window && isUrlMatchingRegex(window.location.href, conditionsUrl); },
    not_regex: function (conditionsUrl) { return !!window && !isUrlMatchingRegex(window.location.href, conditionsUrl); },
    exact: function (conditionsUrl) { return (window === null || window === void 0 ? void 0 : window.location.href) === conditionsUrl; },
    is_not: function (conditionsUrl) { return (window === null || window === void 0 ? void 0 : window.location.href) !== conditionsUrl; },
};
function getRatingBucketForResponseValue(responseValue, scale) {
    if (scale === 3) {
        if (responseValue < 1 || responseValue > 3) {
            throw new Error('The response must be in range 1-3');
        }
        return responseValue === 1 ? 'negative' : responseValue === 2 ? 'neutral' : 'positive';
    }
    else if (scale === 5) {
        if (responseValue < 1 || responseValue > 5) {
            throw new Error('The response must be in range 1-5');
        }
        return responseValue <= 2 ? 'negative' : responseValue === 3 ? 'neutral' : 'positive';
    }
    else if (scale === 7) {
        if (responseValue < 1 || responseValue > 7) {
            throw new Error('The response must be in range 1-7');
        }
        return responseValue <= 3 ? 'negative' : responseValue === 4 ? 'neutral' : 'positive';
    }
    else if (scale === 10) {
        if (responseValue < 0 || responseValue > 10) {
            throw new Error('The response must be in range 0-10');
        }
        return responseValue <= 6 ? 'detractors' : responseValue <= 8 ? 'passives' : 'promoters';
    }
    throw new Error('The scale must be one of: 3, 5, 7, 10');
}
export function getNextSurveyStep(survey, currentQuestionIndex, response) {
    var _a, _b, _c, _d, _e;
    var question = survey.questions[currentQuestionIndex];
    var nextQuestionIndex = currentQuestionIndex + 1;
    if (!((_a = question.branching) === null || _a === void 0 ? void 0 : _a.type)) {
        if (currentQuestionIndex === survey.questions.length - 1) {
            return SurveyQuestionBranchingType.End;
        }
        return nextQuestionIndex;
    }
    if (question.branching.type === SurveyQuestionBranchingType.End) {
        return SurveyQuestionBranchingType.End;
    }
    else if (question.branching.type === SurveyQuestionBranchingType.SpecificQuestion) {
        if (Number.isInteger(question.branching.index)) {
            return question.branching.index;
        }
    }
    else if (question.branching.type === SurveyQuestionBranchingType.ResponseBased) {
        // Single choice
        if (question.type === SurveyQuestionType.SingleChoice) {
            // :KLUDGE: for now, look up the choiceIndex based on the response
            // TODO: once QuestionTypes.MultipleChoiceQuestion is refactored, pass the selected choiceIndex into this method
            var selectedChoiceIndex = question.choices.indexOf("".concat(response));
            if ((_c = (_b = question.branching) === null || _b === void 0 ? void 0 : _b.responseValues) === null || _c === void 0 ? void 0 : _c.hasOwnProperty(selectedChoiceIndex)) {
                var nextStep = question.branching.responseValues[selectedChoiceIndex];
                // Specific question
                if (Number.isInteger(nextStep)) {
                    return nextStep;
                }
                if (nextStep === SurveyQuestionBranchingType.End) {
                    return SurveyQuestionBranchingType.End;
                }
                return nextQuestionIndex;
            }
        }
        else if (question.type === SurveyQuestionType.Rating) {
            if (typeof response !== 'number' || !Number.isInteger(response)) {
                throw new Error('The response type must be an integer');
            }
            var ratingBucket = getRatingBucketForResponseValue(response, question.scale);
            if ((_e = (_d = question.branching) === null || _d === void 0 ? void 0 : _d.responseValues) === null || _e === void 0 ? void 0 : _e.hasOwnProperty(ratingBucket)) {
                var nextStep = question.branching.responseValues[ratingBucket];
                // Specific question
                if (Number.isInteger(nextStep)) {
                    return nextStep;
                }
                if (nextStep === SurveyQuestionBranchingType.End) {
                    return SurveyQuestionBranchingType.End;
                }
                return nextQuestionIndex;
            }
        }
        return nextQuestionIndex;
    }
    logger.warn('Falling back to next question index due to unexpected branching type');
    return nextQuestionIndex;
}
// use urlMatchType to validate url condition, fallback to contains for backwards compatibility
export function doesSurveyUrlMatch(survey) {
    var _a, _b, _c;
    if (!((_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.url)) {
        return true;
    }
    return surveyUrlValidationMap[(_c = (_b = survey.conditions) === null || _b === void 0 ? void 0 : _b.urlMatchType) !== null && _c !== void 0 ? _c : 'icontains'](survey.conditions.url);
}
var PostHogSurveys = /** @class */ (function () {
    function PostHogSurveys(instance) {
        this.instance = instance;
        this.getNextSurveyStep = getNextSurveyStep;
        // we set this to undefined here because we need the persistence storage for this type
        // but that's not initialized until loadIfEnabled is called.
        this._surveyEventReceiver = null;
    }
    PostHogSurveys.prototype.onRemoteConfig = function (response) {
        this._decideServerResponse = !!response['surveys'];
        logger.info("decideServerResponse set to ".concat(this._decideServerResponse));
        this.loadIfEnabled();
    };
    PostHogSurveys.prototype.reset = function () {
        localStorage.removeItem('lastSeenSurveyDate');
        var surveyKeys = getSurveySeenStorageKeys();
        surveyKeys.forEach(function (key) { return localStorage.removeItem(key); });
    };
    PostHogSurveys.prototype.loadIfEnabled = function () {
        var _this = this;
        if (this._surveyManager) {
            // Surveys already loaded.
            return;
        }
        var disableSurveys = this.instance.config.disable_surveys;
        if (disableSurveys) {
            logger.info('Disabled. Not loading surveys.');
            return;
        }
        var phExtensions = assignableWindow === null || assignableWindow === void 0 ? void 0 : assignableWindow.__PosthogExtensions__;
        if (!phExtensions) {
            logger.error('PostHog Extensions not found.');
            return;
        }
        var generateSurveys = phExtensions.generateSurveys;
        if (!this._decideServerResponse) {
            logger.warn('Decide not loaded yet. Not loading surveys.');
            return;
        }
        if (this._surveyEventReceiver == null) {
            this._surveyEventReceiver = new SurveyEventReceiver(this.instance);
        }
        if (!generateSurveys) {
            var loadExternalDependency = phExtensions.loadExternalDependency;
            if (loadExternalDependency) {
                loadExternalDependency(this.instance, 'surveys', function (err) {
                    var _a;
                    if (err) {
                        logger.error('Could not load surveys script', err);
                        return;
                    }
                    _this._surveyManager = (_a = phExtensions.generateSurveys) === null || _a === void 0 ? void 0 : _a.call(phExtensions, _this.instance);
                });
            }
            else {
                logger.error('PostHog loadExternalDependency extension not found. Cannot load remote config.');
            }
        }
        else {
            this._surveyManager = generateSurveys(this.instance);
        }
    };
    PostHogSurveys.prototype.getSurveys = function (callback, forceReload) {
        var _this = this;
        if (forceReload === void 0) { forceReload = false; }
        // In case we manage to load the surveys script, but config says not to load surveys
        // then we shouldn't return survey data
        if (this.instance.config.disable_surveys) {
            logger.info('Disabled. Not loading surveys.');
            return callback([]);
        }
        if (this._surveyEventReceiver == null) {
            this._surveyEventReceiver = new SurveyEventReceiver(this.instance);
        }
        var existingSurveys = this.instance.get_property(SURVEYS);
        if (!existingSurveys || forceReload) {
            this.instance._send_request({
                url: this.instance.requestRouter.endpointFor('api', "/api/surveys/?token=".concat(this.instance.config.token)),
                method: 'GET',
                callback: function (response) {
                    var _a;
                    var _b, _c;
                    var statusCode = response.statusCode;
                    if (statusCode !== 200 || !response.json) {
                        logger.error("Surveys API could not be loaded, status: ".concat(statusCode));
                        return callback([]);
                    }
                    var surveys = response.json.surveys || [];
                    var eventOrActionBasedSurveys = surveys.filter(function (survey) {
                        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
                        return (((_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.events) &&
                            ((_c = (_b = survey.conditions) === null || _b === void 0 ? void 0 : _b.events) === null || _c === void 0 ? void 0 : _c.values) &&
                            ((_f = (_e = (_d = survey.conditions) === null || _d === void 0 ? void 0 : _d.events) === null || _e === void 0 ? void 0 : _e.values) === null || _f === void 0 ? void 0 : _f.length) > 0) ||
                            (((_g = survey.conditions) === null || _g === void 0 ? void 0 : _g.actions) &&
                                ((_j = (_h = survey.conditions) === null || _h === void 0 ? void 0 : _h.actions) === null || _j === void 0 ? void 0 : _j.values) &&
                                ((_m = (_l = (_k = survey.conditions) === null || _k === void 0 ? void 0 : _k.actions) === null || _l === void 0 ? void 0 : _l.values) === null || _m === void 0 ? void 0 : _m.length) > 0);
                    });
                    if (eventOrActionBasedSurveys.length > 0) {
                        (_b = _this._surveyEventReceiver) === null || _b === void 0 ? void 0 : _b.register(eventOrActionBasedSurveys);
                    }
                    (_c = _this.instance.persistence) === null || _c === void 0 ? void 0 : _c.register((_a = {}, _a[SURVEYS] = surveys, _a));
                    return callback(surveys);
                },
            });
        }
        else {
            logger.info('Surveys already loaded, using existing data.');
            return callback(existingSurveys);
        }
    };
    PostHogSurveys.prototype.getActiveMatchingSurveys = function (callback, forceReload) {
        var _this = this;
        if (forceReload === void 0) { forceReload = false; }
        this.getSurveys(function (surveys) {
            var _a;
            var activeSurveys = surveys.filter(function (survey) {
                return !!(survey.start_date && !survey.end_date);
            });
            var conditionMatchedSurveys = activeSurveys.filter(function (survey) {
                var _a;
                if (!survey.conditions) {
                    return true;
                }
                var urlCheck = doesSurveyUrlMatch(survey);
                var selectorCheck = ((_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.selector)
                    ? document === null || document === void 0 ? void 0 : document.querySelector(survey.conditions.selector)
                    : true;
                return urlCheck && selectorCheck;
            });
            // get all the surveys that have been activated so far with user actions.
            var activatedSurveys = (_a = _this._surveyEventReceiver) === null || _a === void 0 ? void 0 : _a.getSurveys();
            var targetingMatchedSurveys = conditionMatchedSurveys.filter(function (survey) {
                var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
                if (!survey.linked_flag_key &&
                    !survey.targeting_flag_key &&
                    !survey.internal_targeting_flag_key &&
                    !((_a = survey.feature_flag_keys) === null || _a === void 0 ? void 0 : _a.length)) {
                    return true;
                }
                var linkedFlagCheck = survey.linked_flag_key
                    ? _this.instance.featureFlags.isFeatureEnabled(survey.linked_flag_key)
                    : true;
                var targetingFlagCheck = survey.targeting_flag_key
                    ? _this.instance.featureFlags.isFeatureEnabled(survey.targeting_flag_key)
                    : true;
                var hasEvents = ((_b = survey.conditions) === null || _b === void 0 ? void 0 : _b.events) &&
                    ((_d = (_c = survey.conditions) === null || _c === void 0 ? void 0 : _c.events) === null || _d === void 0 ? void 0 : _d.values) &&
                    ((_f = (_e = survey.conditions) === null || _e === void 0 ? void 0 : _e.events) === null || _f === void 0 ? void 0 : _f.values.length) > 0;
                var hasActions = ((_g = survey.conditions) === null || _g === void 0 ? void 0 : _g.actions) &&
                    ((_j = (_h = survey.conditions) === null || _h === void 0 ? void 0 : _h.actions) === null || _j === void 0 ? void 0 : _j.values) &&
                    ((_l = (_k = survey.conditions) === null || _k === void 0 ? void 0 : _k.actions) === null || _l === void 0 ? void 0 : _l.values.length) > 0;
                var eventBasedTargetingFlagCheck = hasEvents || hasActions ? activatedSurveys === null || activatedSurveys === void 0 ? void 0 : activatedSurveys.includes(survey.id) : true;
                var overrideInternalTargetingFlagCheck = _this._canActivateRepeatedly(survey);
                var internalTargetingFlagCheck = survey.internal_targeting_flag_key && !overrideInternalTargetingFlagCheck
                    ? _this.instance.featureFlags.isFeatureEnabled(survey.internal_targeting_flag_key)
                    : true;
                var flagsCheck = _this.checkFlags(survey);
                return (linkedFlagCheck &&
                    targetingFlagCheck &&
                    internalTargetingFlagCheck &&
                    eventBasedTargetingFlagCheck &&
                    flagsCheck);
            });
            return callback(targetingMatchedSurveys);
        }, forceReload);
    };
    PostHogSurveys.prototype.checkFlags = function (survey) {
        var _this = this;
        var _a;
        if (!((_a = survey.feature_flag_keys) === null || _a === void 0 ? void 0 : _a.length)) {
            return true;
        }
        return survey.feature_flag_keys.every(function (_a) {
            var key = _a.key, value = _a.value;
            if (!key || !value) {
                return true;
            }
            return _this.instance.featureFlags.isFeatureEnabled(value);
        });
    };
    // this method is lazily loaded onto the window to avoid loading preact and other dependencies if surveys is not enabled
    PostHogSurveys.prototype._canActivateRepeatedly = function (survey) {
        var _a;
        if (isNullish((_a = assignableWindow.__PosthogExtensions__) === null || _a === void 0 ? void 0 : _a.canActivateRepeatedly)) {
            logger.warn('init was not called');
            return false; // TODO does it make sense to have a default here?
        }
        return assignableWindow.__PosthogExtensions__.canActivateRepeatedly(survey);
    };
    PostHogSurveys.prototype.canRenderSurvey = function (surveyId) {
        var _this = this;
        if (isNullish(this._surveyManager)) {
            logger.warn('init was not called');
            return;
        }
        this.getSurveys(function (surveys) {
            var survey = surveys.filter(function (x) { return x.id === surveyId; })[0];
            _this._surveyManager.canRenderSurvey(survey);
        });
    };
    PostHogSurveys.prototype.renderSurvey = function (surveyId, selector) {
        var _this = this;
        if (isNullish(this._surveyManager)) {
            logger.warn('init was not called');
            return;
        }
        this.getSurveys(function (surveys) {
            var survey = surveys.filter(function (x) { return x.id === surveyId; })[0];
            _this._surveyManager.renderSurvey(survey, document === null || document === void 0 ? void 0 : document.querySelector(selector));
        });
    };
    return PostHogSurveys;
}());
export { PostHogSurveys };
//# sourceMappingURL=posthog-surveys.js.map