/*
 * Application Insights JavaScript SDK - Core, 3.2.0
 * Copyright (c) Microsoft and contributors. All rights reserved.
 */
var _a, _b;
import { arrForEach, arrIndexOf, dumpObj, getDocument, getLazy, getNavigator, isArray, isFunction, isNullOrUndefined, isString, isTruthy, isUndefined, objForEachKey, strEndsWith, strIndexOf, strLeft, strSubstring, strTrim, utcNow } from "@nevware21/ts-utils";
import { cfgDfMerge } from "../Config/ConfigDefaultHelpers";
import { createDynamicConfig, onConfigChange } from "../Config/DynamicConfig";
import { _DYN_ENABLED, _DYN_LENGTH, _DYN_LOGGER, _DYN_PROTOCOL, _DYN_SET_DF, _DYN_SPLIT, _DYN_UNLOAD, _DYN_USER_AGENT } from "../__DynamicConstants";
import { _throwInternal } from "./DiagnosticLogger";
import { getLocation, isIE } from "./EnvUtils";
import { getExceptionName, isNotNullOrUndefined, setValue, strContains } from "./HelperFuncs";
import { STR_DOMAIN, STR_EMPTY, STR_PATH, UNDEFINED_VALUE } from "./InternalConstants";
var strToGMTString = "toGMTString";
var strToUTCString = "toUTCString";
var strCookie = "cookie";
var strExpires = "expires";
var strIsCookieUseDisabled = "isCookieUseDisabled";
var strDisableCookiesUsage = "disableCookiesUsage";
var strConfigCookieMgr = "_ckMgr";
var _supportsCookies = null;
var _allowUaSameSite = null;
var _parsedCookieValue = null;
var _doc;
var _cookieCache = {};
var _globalCookieConfig = {};
// // `isCookieUseDisabled` is deprecated, so explicitly casting as a key of IConfiguration to avoid typing error
// // when both isCookieUseDisabled and disableCookiesUsage are used disableCookiesUsage will take precedent, which is
// // why its listed first
/**
 * Set the supported dynamic config values as undefined (or an empty object) so that
 * any listeners will be informed of any changes.
 * Explicitly NOT including the deprecated `isCookieUseDisabled` as we don't want to support
 * the v1 deprecated field as dynamic for updates
 */
var rootDefaultConfig = (_a = {
        cookieCfg: cfgDfMerge((_b = {},
            _b[STR_DOMAIN] = { fb: "cookieDomain", dfVal: isNotNullOrUndefined },
            _b.path = { fb: "cookiePath", dfVal: isNotNullOrUndefined },
            _b.enabled = UNDEFINED_VALUE,
            _b.ignoreCookies = UNDEFINED_VALUE,
            _b.blockedCookies = UNDEFINED_VALUE,
            _b)),
        cookieDomain: UNDEFINED_VALUE,
        cookiePath: UNDEFINED_VALUE
    },
    _a[strDisableCookiesUsage] = UNDEFINED_VALUE,
    _a);
function _getDoc() {
    !_doc && (_doc = getLazy(function () { return getDocument(); }));
}
/**
 * @ignore
 * DO NOT USE or export from the module, this is exposed as public to support backward compatibility of previous static utility methods only.
 * If you want to manager cookies either use the ICookieMgr available from the core instance via getCookieMgr() or create
 * your own instance of the CookieMgr and use that.
 * Using this directly for enabling / disabling cookie handling will not only affect your usage but EVERY user of cookies.
 * Example, if you are using a shared component that is also using Application Insights you will affect their cookie handling.
 * @param logger - The DiagnosticLogger to use for reporting errors.
 */
function _gblCookieMgr(config, logger) {
    // Stash the global instance against the BaseCookieMgr class
    var inst = createCookieMgr[strConfigCookieMgr] || _globalCookieConfig[strConfigCookieMgr];
    if (!inst) {
        // Note: not using the getSetValue() helper as that would require always creating a temporary cookieMgr
        // that ultimately is never used
        inst = createCookieMgr[strConfigCookieMgr] = createCookieMgr(config, logger);
        _globalCookieConfig[strConfigCookieMgr] = inst;
    }
    return inst;
}
function _isMgrEnabled(cookieMgr) {
    if (cookieMgr) {
        return cookieMgr.isEnabled();
    }
    return true;
}
function _isIgnoredCookie(cookieMgrCfg, name) {
    if (name && cookieMgrCfg && isArray(cookieMgrCfg.ignoreCookies)) {
        return arrIndexOf(cookieMgrCfg.ignoreCookies, name) !== -1;
    }
    return false;
}
function _isBlockedCookie(cookieMgrCfg, name) {
    if (name && cookieMgrCfg && isArray(cookieMgrCfg.blockedCookies)) {
        if (arrIndexOf(cookieMgrCfg.blockedCookies, name) !== -1) {
            return true;
        }
    }
    return _isIgnoredCookie(cookieMgrCfg, name);
}
function _isCfgEnabled(rootConfig, cookieMgrConfig) {
    var isCfgEnabled = cookieMgrConfig[_DYN_ENABLED /* @min:%2eenabled */];
    if (isNullOrUndefined(isCfgEnabled)) {
        // Set the enabled from the provided setting or the legacy root values
        var cookieEnabled = void 0;
        // This field is deprecated and dynamic updates will not be fully supported
        if (!isUndefined(rootConfig[strIsCookieUseDisabled])) {
            cookieEnabled = !rootConfig[strIsCookieUseDisabled];
        }
        // If this value is defined it takes precedent over the above
        if (!isUndefined(rootConfig[strDisableCookiesUsage])) {
            cookieEnabled = !rootConfig[strDisableCookiesUsage];
        }
        // Not setting the cookieMgrConfig.enabled as that will update (set) the global dynamic config
        // So future "updates" then may not be as expected
        isCfgEnabled = cookieEnabled;
    }
    return isCfgEnabled;
}
/**
 * Helper to return the ICookieMgr from the core (if not null/undefined) or a default implementation
 * associated with the configuration or a legacy default.
 * @param core
 * @param config
 * @returns
 */
export function safeGetCookieMgr(core, config) {
    var cookieMgr;
    if (core) {
        // Always returns an instance
        cookieMgr = core.getCookieMgr();
    }
    else if (config) {
        var cookieCfg = config.cookieCfg;
        if (cookieCfg && cookieCfg[strConfigCookieMgr]) {
            cookieMgr = cookieCfg[strConfigCookieMgr];
        }
        else {
            cookieMgr = createCookieMgr(config);
        }
    }
    if (!cookieMgr) {
        // Get or initialize the default global (legacy) cookie manager if we couldn't find one
        cookieMgr = _gblCookieMgr(config, (core || {})[_DYN_LOGGER /* @min:%2elogger */]);
    }
    return cookieMgr;
}
export function createCookieMgr(rootConfig, logger) {
    var _a;
    var cookieMgrConfig;
    var _path;
    var _domain;
    var unloadHandler;
    // Explicitly checking against false, so that setting to undefined will === true
    var _enabled;
    var _getCookieFn;
    var _setCookieFn;
    var _delCookieFn;
    // Make sure the root config is dynamic as it may be the global config
    rootConfig = createDynamicConfig(rootConfig || _globalCookieConfig, null, logger).cfg;
    // Will get recalled if the referenced configuration is changed
    unloadHandler = onConfigChange(rootConfig, function (details) {
        // Make sure the root config has all of the the defaults to the root config to ensure they are dynamic
        details[_DYN_SET_DF /* @min:%2esetDf */](details.cfg, rootDefaultConfig);
        // Create and apply the defaults to the cookieCfg element
        cookieMgrConfig = details.ref(details.cfg, "cookieCfg"); // details.setDf(details.cfg.cookieCfg, defaultConfig);
        _path = cookieMgrConfig[STR_PATH /* @min:%2epath */] || "/";
        _domain = cookieMgrConfig[STR_DOMAIN /* @min:%2edomain */];
        // Explicitly checking against false, so that setting to undefined will === true
        _enabled = _isCfgEnabled(rootConfig, cookieMgrConfig) !== false;
        _getCookieFn = cookieMgrConfig.getCookie || _getCookieValue;
        _setCookieFn = cookieMgrConfig.setCookie || _setCookieValue;
        _delCookieFn = cookieMgrConfig.delCookie || _setCookieValue;
    }, logger);
    var cookieMgr = (_a = {
            isEnabled: function () {
                var enabled = _isCfgEnabled(rootConfig, cookieMgrConfig) !== false && _enabled && areCookiesSupported(logger);
                // Using an indirect lookup for any global cookie manager to support tree shaking for SDK's
                // that don't use the "applicationinsights-core" version of the default cookie function
                var gblManager = _globalCookieConfig[strConfigCookieMgr];
                if (enabled && gblManager && cookieMgr !== gblManager) {
                    // Make sure the GlobalCookie Manager instance (if not this instance) is also enabled.
                    // As the global (deprecated) functions may have been called (for backward compatibility)
                    enabled = _isMgrEnabled(gblManager);
                }
                return enabled;
            },
            setEnabled: function (value) {
                // Explicitly checking against false, so that setting to undefined will === true
                _enabled = value !== false;
                cookieMgrConfig[_DYN_ENABLED /* @min:%2eenabled */] = value;
            },
            set: function (name, value, maxAgeSec, domain, path) {
                var result = false;
                if (_isMgrEnabled(cookieMgr) && !_isBlockedCookie(cookieMgrConfig, name)) {
                    var values = {};
                    var theValue = strTrim(value || STR_EMPTY);
                    var idx = strIndexOf(theValue, ";");
                    if (idx !== -1) {
                        theValue = strTrim(strLeft(value, idx));
                        values = _extractParts(strSubstring(value, idx + 1));
                    }
                    // Only update domain if not already present (isUndefined) and the value is truthy (not null, undefined or empty string)
                    setValue(values, STR_DOMAIN, domain || _domain, isTruthy, isUndefined);
                    if (!isNullOrUndefined(maxAgeSec)) {
                        var _isIE = isIE();
                        if (isUndefined(values[strExpires])) {
                            var nowMs = utcNow();
                            // Only add expires if not already present
                            var expireMs = nowMs + (maxAgeSec * 1000);
                            // Sanity check, if zero or -ve then ignore
                            if (expireMs > 0) {
                                var expiry = new Date();
                                expiry.setTime(expireMs);
                                setValue(values, strExpires, _formatDate(expiry, !_isIE ? strToUTCString : strToGMTString) || _formatDate(expiry, _isIE ? strToGMTString : strToUTCString) || STR_EMPTY, isTruthy);
                            }
                        }
                        if (!_isIE) {
                            // Only replace if not already present
                            setValue(values, "max-age", STR_EMPTY + maxAgeSec, null, isUndefined);
                        }
                    }
                    var location_1 = getLocation();
                    if (location_1 && location_1[_DYN_PROTOCOL /* @min:%2eprotocol */] === "https:") {
                        setValue(values, "secure", null, null, isUndefined);
                        // Only set same site if not also secure
                        if (_allowUaSameSite === null) {
                            _allowUaSameSite = !uaDisallowsSameSiteNone((getNavigator() || {})[_DYN_USER_AGENT /* @min:%2euserAgent */]);
                        }
                        if (_allowUaSameSite) {
                            setValue(values, "SameSite", "None", null, isUndefined);
                        }
                    }
                    setValue(values, STR_PATH, path || _path, null, isUndefined);
                    //let setCookieFn = cookieMgrConfig.setCookie || _setCookieValue;
                    _setCookieFn(name, _formatCookieValue(theValue, values));
                    result = true;
                }
                return result;
            },
            get: function (name) {
                var value = STR_EMPTY;
                if (_isMgrEnabled(cookieMgr) && !_isIgnoredCookie(cookieMgrConfig, name)) {
                    value = _getCookieFn(name);
                }
                return value;
            },
            del: function (name, path) {
                var result = false;
                if (_isMgrEnabled(cookieMgr)) {
                    // Only remove the cookie if the manager and cookie support has not been disabled
                    result = cookieMgr.purge(name, path);
                }
                return result;
            },
            purge: function (name, path) {
                var _a;
                var result = false;
                if (areCookiesSupported(logger)) {
                    // Setting the expiration date in the past immediately removes the cookie
                    var values = (_a = {},
                        _a[STR_PATH] = path ? path : "/",
                        _a[strExpires] = "Thu, 01 Jan 1970 00:00:01 GMT",
                        _a);
                    if (!isIE()) {
                        // Set max age to expire now
                        values["max-age"] = "0";
                    }
                    // let delCookie = cookieMgrConfig.delCookie || _setCookieValue;
                    _delCookieFn(name, _formatCookieValue(STR_EMPTY, values));
                    result = true;
                }
                return result;
            }
        },
        _a[_DYN_UNLOAD /* @min:unload */] = function (isAsync) {
            unloadHandler && unloadHandler.rm();
            unloadHandler = null;
        },
        _a);
    // Associated this cookie manager with the config
    cookieMgr[strConfigCookieMgr] = cookieMgr;
    return cookieMgr;
}
/*
* Helper method to tell if document.cookie object is supported by the runtime
*/
export function areCookiesSupported(logger) {
    if (_supportsCookies === null) {
        _supportsCookies = false;
        !_doc && _getDoc();
        try {
            var doc = _doc.v || {};
            _supportsCookies = doc[strCookie] !== undefined;
        }
        catch (e) {
            _throwInternal(logger, 2 /* eLoggingSeverity.WARNING */, 68 /* _eInternalMessageId.CannotAccessCookie */, "Cannot access document.cookie - " + getExceptionName(e), { exception: dumpObj(e) });
        }
    }
    return _supportsCookies;
}
function _extractParts(theValue) {
    var values = {};
    if (theValue && theValue[_DYN_LENGTH /* @min:%2elength */]) {
        var parts = strTrim(theValue)[_DYN_SPLIT /* @min:%2esplit */](";");
        arrForEach(parts, function (thePart) {
            thePart = strTrim(thePart || STR_EMPTY);
            if (thePart) {
                var idx = strIndexOf(thePart, "=");
                if (idx === -1) {
                    values[thePart] = null;
                }
                else {
                    values[strTrim(strLeft(thePart, idx))] = strTrim(strSubstring(thePart, idx + 1));
                }
            }
        });
    }
    return values;
}
function _formatDate(theDate, func) {
    if (isFunction(theDate[func])) {
        return theDate[func]();
    }
    return null;
}
function _formatCookieValue(value, values) {
    var cookieValue = value || STR_EMPTY;
    objForEachKey(values, function (name, theValue) {
        cookieValue += "; " + name + (!isNullOrUndefined(theValue) ? "=" + theValue : STR_EMPTY);
    });
    return cookieValue;
}
function _getCookieValue(name) {
    var cookieValue = STR_EMPTY;
    !_doc && _getDoc();
    if (_doc.v) {
        var theCookie = _doc.v[strCookie] || STR_EMPTY;
        if (_parsedCookieValue !== theCookie) {
            _cookieCache = _extractParts(theCookie);
            _parsedCookieValue = theCookie;
        }
        cookieValue = strTrim(_cookieCache[name] || STR_EMPTY);
    }
    return cookieValue;
}
function _setCookieValue(name, cookieValue) {
    !_doc && _getDoc();
    if (_doc.v) {
        _doc.v[strCookie] = name + "=" + cookieValue;
    }
}
export function uaDisallowsSameSiteNone(userAgent) {
    if (!isString(userAgent)) {
        return false;
    }
    // Cover all iOS based browsers here. This includes:
    // - Safari on iOS 12 for iPhone, iPod Touch, iPad
    // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
    // - Chrome on iOS 12 for iPhone, iPod Touch, iPad
    // All of which are broken by SameSite=None, because they use the iOS networking stack
    if (strContains(userAgent, "CPU iPhone OS 12") || strContains(userAgent, "iPad; CPU OS 12")) {
        return true;
    }
    // Cover Mac OS X based browsers that use the Mac OS networking stack. This includes:
    // - Safari on Mac OS X
    // This does not include:
    // - Internal browser on Mac OS X
    // - Chrome on Mac OS X
    // - Chromium on Mac OS X
    // Because they do not use the Mac OS networking stack.
    if (strContains(userAgent, "Macintosh; Intel Mac OS X 10_14") && strContains(userAgent, "Version/") && strContains(userAgent, "Safari")) {
        return true;
    }
    // Cover Mac OS X internal browsers that use the Mac OS networking stack. This includes:
    // - Internal browser on Mac OS X
    // This does not include:
    // - Safari on Mac OS X
    // - Chrome on Mac OS X
    // - Chromium on Mac OS X
    // Because they do not use the Mac OS networking stack.
    if (strContains(userAgent, "Macintosh; Intel Mac OS X 10_14") && strEndsWith(userAgent, "AppleWebKit/605.1.15 (KHTML, like Gecko)")) {
        return true;
    }
    // Cover Chrome 50-69, because some versions are broken by SameSite=None, and none in this range require it.
    // Note: this covers some pre-Chromium Edge versions, but pre-Chromim Edge does not require SameSite=None, so this is fine.
    // Note: this regex applies to Windows, Mac OS X, and Linux, deliberately.
    if (strContains(userAgent, "Chrome/5") || strContains(userAgent, "Chrome/6")) {
        return true;
    }
    // Unreal Engine runs Chromium 59, but does not advertise as Chrome until 4.23. Treat versions of Unreal
    // that don't specify their Chrome version as lacking support for SameSite=None.
    if (strContains(userAgent, "UnrealEngine") && !strContains(userAgent, "Chrome")) {
        return true;
    }
    // UCBrowser < 12.13.2 ignores Set-Cookie headers with SameSite=None
    // NB: this rule isn't complete - you need regex to make a complete rule.
    // See: https://www.chromium.org/updates/same-site/incompatible-clients
    if (strContains(userAgent, "UCBrowser/12") || strContains(userAgent, "UCBrowser/11")) {
        return true;
    }
    return false;
}
//# sourceMappingURL=CookieMgr.js.map