import { K as KlevuFilterType } from './KlevuApiRawResponse.js';
import './KlevuSearchSorting.js';
import { i as isBrowser, a as KlevuConfig, K as KlevuStorage, S as StorageType, b as KlevuIpResolver, c as KlevuEventV2CheckedOutProducts, U as USER_SESSION_ID_STORAGE_KEY, d as KlevuEventV2, e as KlevuEventV1ProductTracking, f as KlevuEventV1Search, h as KlevuEventV1CategoryView, j as KlevuEventV1CategoryProductClick, k as KlevuEventV1BannerClick, g as get, p as post } from './config.js';
import { K as KlevuDomEvents } from './KlevuDomEvents.js';
import { K as KlevuLastSearches } from './lastSearches.js';
import { a as KlevuKMCSettings } from './klevu-init2.js';

/**
 * transform object to query parameters
 *
 * @param params
 */
function objectToQueryParameters(params) {
    let urlData = "?";
    for (const [key, value] of Object.entries(params)) {
        if (value === undefined) {
            continue;
        }
        urlData += `${key}=${encodeURIComponent(value)}&`;
    }
    return urlData;
}

var AdvancedSortingDiretion;
(function (AdvancedSortingDiretion) {
    AdvancedSortingDiretion["Ascending"] = "ASC";
    AdvancedSortingDiretion["Descending"] = "DESC";
})(AdvancedSortingDiretion || (AdvancedSortingDiretion = {}));

var KlevuFilterOrder;
(function (KlevuFilterOrder) {
    /**
     * Sort options based on the number of records each option has in the result
     * set.
     */
    KlevuFilterOrder["Frequency"] = "FREQ";
    /**
     * 'INDEX' will sort the options alphabetically.
     */
    KlevuFilterOrder["Index"] = "INDEX";
})(KlevuFilterOrder || (KlevuFilterOrder = {}));

var KlevuSearchPreference;
(function (KlevuSearchPreference) {
    KlevuSearchPreference["showOutOfStockProducts"] = "showOutOfStockProducts";
    /**
     * 	Whether or not your store should include 'Out of Stock' products in search
     * 	results by default can be configured within the Klevu Merchant Centre.
     * 	However, if you would like to override this for a particular query, please
     * 	include one of these flags.
     */
    KlevuSearchPreference["hideOutOfStockProducts"] = "hideOutOfStockProducts";
    /**
     * 	This can be used in conjunction with showOutOfStockProducts. If your store
     * 	is configured to display out of stock products, they will be displayed at
     * 	the very end of the search results after all in stock products have been
     * 	displayed. By using this flag you can disable this logic, and cause all
     * 	products to be ranked in an order that disregards their stock status.
     */
    KlevuSearchPreference["disableStockSorting"] = "disableStockSorting";
    /**
     * 	By default, functional words such as prepositions, pronouns, articles,
     * 	etc. are excluded from searches. Add this flag to include these stopwords
     * 	in your search.
     */
    KlevuSearchPreference["includeStopwords"] = "includeStopwords";
    /**
     * 	Use this flag to disable the searching of record IDs.
     */
    KlevuSearchPreference["excludeIds"] = "excludeIds";
    /**
     * , excludeDescription Whether or not a record's 'description' is considered
     * for search results can be configured by Klevu Support on a store by store
     * basis, however if you would like to override this for a particular query,
     * please include one of these flags.
     */
    KlevuSearchPreference["includeDescription"] = "includeDescription";
    /**
     * 	This flag can be used in conjunction with the typeOfSearch 'DEFAULT' to
     * 	disable the FUZZY_AND and FUZZY_OR search types from being attempted.
     */
    KlevuSearchPreference["disableFuzzyMatch"] = "disableFuzzyMatch";
    /**
     * 	This flag can be used in conjunction with the typeOfSearch 'DEFAULT' to
     * 	disable the WILDCARD_AND and WILDCARD_OR search types from being
     * 	attempted.
     */
    KlevuSearchPreference["disableWildcard"] = "disableWildcard";
    /**
     * 	This flag can be used in conjunction with the typeOfSearch 'DEFAULT' to
     * 	disable the WILDCARD_OR and FUZZY_OR search types from being attempted.
     */
    KlevuSearchPreference["disableORSearch"] = "disableORSearch";
    /**
     * Enable partial match for the last word of a query, where the last word
     * searched can be a substring of any other word found in a record. This can
     * be useful for non-English languages.
     *
     * For example let's say a product has the name "rödvinsglas" (red wine
     * glass). If searching for "högt glas" (tall glass) it may not match since
     * the record has no words starting with 'glas'. By providing this flag, the
     * search would become "högt *glas*" meaning it would match the record since
     * it contains a word which ends with 'glas'.
     *
     */
    KlevuSearchPreference["partialMatch"] = "partialMatch";
    /**
     * 	Similar to partialMatch, but for all words rather than just the last. In
     * 	the same "rödvinsglas" example, a search for "högt glas" would become
     * 	"*högt* *glas*", so any records containing words containing 'högt' or
     * 	'glas' would result in a match.
     */
    KlevuSearchPreference["partialMatchForAllWords"] = "partialMatchForAllWords";
    /**
     * 	For a query longer than one word, all the possible bigrams and trigrams
     * 	(i.e. formed out of query terms) are looked up in records and the ones
     * 	having one or more of them are boosted higher up in the search results.
     * 	You can use this flag to disable such boosting.
     */
    KlevuSearchPreference["disableWordShingles"] = "disableWordShingles";
    /**
     * When a compound word is searched for, i.e. two or more individual words
     * joined together as one word, Klevu automatically disjoints them if the
     * de-compounding feature is enabled for your store.
     *
     * For example, a search for "fairylights" would be treated as "fairy lights",
     * but with the added condition that those words must appear within 5 words of
     * each other in a matching record.
     *
     * If you would prefer that the words "fairy" and "light" could be found
     * anywhere within the record, not necessarily near one another, then please
     * include this flag.
     */
    KlevuSearchPreference["searchCompoundsAsAndQuery"] = "searchCompoundsAsAndQuery";
    /**
     * 	By default, synonyms are treated equally to their query term. Should you
     * 	wish to give higher priority to the actual terms your customer entered in
     * 	the query over their synonyms, please include this flag in your search
     * 	preferences.
     */
    KlevuSearchPreference["enableBoostingOriginalTermsInSynonyms"] = "enableBoostingOriginalTermsInSynonyms";
    /**
     * It is possible to configure which facets or filters should be enabled or
     * disabled within the Klevu Merchant Centre. By including this flag, all
     * facets will be returned regardless of whether they have been disabled in
     * the KMC.
     */
    KlevuSearchPreference["showDisabledFacets"] = "showDisabledFacets";
    /**
     * By default some filters are excluded from the results if they only have a
     * small number of results. Please use this flag to override this logic and
     * include all filters in the response.
     */
    KlevuSearchPreference["showFiltersWithSmallCount"] = "showFiltersWithSmallCount";
    /**
     * When the typeOfRequest is 'CATNAV', the filter for 'Category' is
     * automatically excluded since you are already within the context of a
     * category. Use this flag to override this logic and return the category
     * filters even for CatNav requests.
     */
    KlevuSearchPreference["includeCategoryFilterInCatNav"] = "includeCategoryFilterInCatNav";
    /**
     * Include the score information with the response fields: score,
     * klevu_manual_boosting, klevu_bulk_boosting and klevu_selflearning_boosting.
     */
    KlevuSearchPreference["enableScores"] = "enableScores";
    /**
     * Use this flag to include additional information about the query execution.
     * This information is populated in the meta object of the response.
     *
     * Please note that it is not recommended to enable this flag in your
     * Production environment, as performance will be impacted.
     */
    KlevuSearchPreference["debugQuery"] = "debugQuery";
    /**
     * @TODO: Most probably ignores manual boostin. Needs proper documentation
     */
    KlevuSearchPreference["ignoreManualBoosting"] = "ignoreManualBoosting";
})(KlevuSearchPreference || (KlevuSearchPreference = {}));

var KlevuTypeOfRecord;
(function (KlevuTypeOfRecord) {
    KlevuTypeOfRecord["Product"] = "KLEVU_PRODUCT";
    KlevuTypeOfRecord["Cms"] = "KLEVU_CMS";
    KlevuTypeOfRecord["Category"] = "KLEVU_CATEGORY";
    KlevuTypeOfRecord["Image"] = "KLEVU_IMAGE";
})(KlevuTypeOfRecord || (KlevuTypeOfRecord = {}));

var KlevuTypeOfRequest;
(function (KlevuTypeOfRequest) {
    KlevuTypeOfRequest["Search"] = "SEARCH";
    KlevuTypeOfRequest["Suggestion"] = "AUTO_SUGGESTIONS";
    KlevuTypeOfRequest["CategoryNavigation"] = "CATNAV";
    KlevuTypeOfRequest["NewArrivals"] = "RECS_NEW_ARRIVALS";
    KlevuTypeOfRequest["SimilarProducts"] = "RECS_SIMILAR";
    KlevuTypeOfRequest["Trending"] = "RECS_TRENDING";
    KlevuTypeOfRequest["AlsoViewed"] = "RECS_ALSO_VIEWED";
    KlevuTypeOfRequest["AlsoBought"] = "RECS_ALSO_BOUGHT";
    KlevuTypeOfRequest["VisuallySimilar"] = "RECS_SIMILAR_IMAGES";
    KlevuTypeOfRequest["Custom"] = "RECS_CUSTOM";
    // Special type where we skip request to Klevu services, but run everything else
    KlevuTypeOfRequest["Skip"] = "SKIP";
})(KlevuTypeOfRequest || (KlevuTypeOfRequest = {}));

var KlevuTypeOfSearch;
(function (KlevuTypeOfSearch) {
    /**
     * When this value is specified, Klevu will go through a number of attempts to
     * find matching records. The first type attempted is WILDCARD_AND. If there
     * aren't any results found, Klevu tries to find products with the FUZZY_AND
     * query type.
     *
     * As long as no matches are found, Klevu will continue to fire different query
     * types in the following order:
     *
     * WILDCARD_AND
     * FUZZY_AND
     * WILDCARD_OR
     * FUZZY_OR
     * Note that when a search term only contains a single word, or more than six
     * words, the 'OR' query types will be skipped.
     */
    KlevuTypeOfSearch["Default"] = "DEFAULT";
    /**
     * This is an 'AND' query so all words of the query must be found somewhere in a
     * record for it to be included in the results. The last word of the query will
     * have a wildcard suffix appended.
     *
     * For example, if the searched query is "hooded jacket", this will become
     * "hooded jacket*", ie. Klevu will try to find records containing the word
     * "hooded" AND any words beginning with "jacket".
     */
    KlevuTypeOfSearch["WildcardAnd"] = "WILDCARD_AND";
    /**
     * This is the same as a WILDCARD_AND query, however a certain amount of
     * 'fuzziness' is allowed to account for spelling mistakes.
     *
     * For example, if the searched query contains spelling mistakes like "hooder
     * jakcet", Klevu will still be able to match any records containing the words
     * "hooded" AND "jacket".
     */
    KlevuTypeOfSearch["FuzzyAnd"] = "FUZZY_AND";
    /**
     * This is an 'OR' query so at least one of the words in the query must be found
     * somewhere in a record for it to be included in the results. The last word of
     * the query will have a wildcard suffix appended.
     *
     * For example, if the searched query is "hooded jacket", this will become
     * "hooded jacket*", ie. Klevu will try to find records containing the word
     * "hooded" OR any words beginning with "jacket".
     */
    KlevuTypeOfSearch["WildcardOr"] = "WILDCARD_OR";
    /**
     * This is the same as a WILDCARD_OR query, however a certain amount of
     * 'fuzziness' is allowed to account for spelling mistakes.
     *
     * For example, if the searched query contains spelling mistakes like "hooder
     * jakcet", Klevu will still be able to match any records containing the words
     * "hooded" OR "jacket".
     */
    KlevuTypeOfSearch["FuzzyOr"] = "FUZZY_OR";
    /**
     * All of the exact words of a query must be found in a record for it to be
     * included in the results. No fuzziness or wildcards are included.
     *
     * For example a search for "hooded jacket" will only return records which
     * contain the exact terms "hooded" AND "jacket".
     */
    KlevuTypeOfSearch["And"] = "AND";
    /**
     * At least one exact word of a query must be found in a record for it to be
     * included in a results. No fuzziness or wildcards are included.
     *
     * For example a search for "hooded jacket" will only return records which
     * contain one of the exact terms "hooded" OR "jacket".
     */
    KlevuTypeOfSearch["Or"] = "OR";
})(KlevuTypeOfSearch || (KlevuTypeOfSearch = {}));

/**
 * Internal function to inject listFilter results back to result object when they are removed in next() function
 * Should not be used outside of library itself
 *
 * @category Modifier
 * @param prevQuery
 * @returns
 */
function injectFilterResult(prevQuery) {
    return {
        klevuModifierId: "injectFilteResult",
        onResult: (response) => {
            var _a, _b;
            const copy = Object.assign({}, response);
            const found = (_b = (_a = copy.apiResponse) === null || _a === void 0 ? void 0 : _a.queryResults) === null || _b === void 0 ? void 0 : _b.find((q) => q.id === prevQuery.id);
            if (found) {
                found.filters = prevQuery.filters;
            }
            return copy;
        },
    };
}

/**
 * @ignore
 */
class KlevuFetchCache {
    constructor() {
        this._cache = new Map();
        this._timestamp = new Map();
    }
    /**
     * checks if cache has value and returns it
     *
     * @param key
     * @param force For testing purposes
     * @returns undefined if not cached
     */
    check(key, force = false) {
        // never cache on node server
        if (!force && !isBrowser()) {
            return undefined;
        }
        const hash = this.hash(key);
        if (!this._cache.has(hash)) {
            return undefined;
        }
        const cached = this._cache.get(hash);
        const ts = this._timestamp.get(hash);
        if (cached && ts) {
            if (new Date().getTime() < ts) {
                return JSON.parse(cached);
            }
            this._cache.delete(hash);
            this._timestamp.delete(hash);
        }
        return undefined;
    }
    cache(key, data, timetocache = KlevuConfig.getDefault().cacheMaxTTL) {
        const hash = this.hash(key);
        this._cache.set(hash, JSON.stringify(data));
        this._timestamp.set(hash, new Date().getTime() + timetocache);
    }
    hash(input) {
        return Array.from(JSON.stringify(input)).reduce((s, c) => (Math.imul(31, s) + c.charCodeAt(0)) | 0, 0);
    }
}

/**
 * Type safe version to remove nulls and undefineds from array
 *
 * usage: `myArray.filter(notEmpty)`
 *
 * @param value
 * @returns
 */
function notEmpty(value) {
    return value !== null && value !== undefined;
}

const ONE_HOUR = 36000000;
const LAST_CLICKED_STORAGE_KEY = "klevu-last-clicks";
const LAST_CLICKED_CATEGORY_STORAGE_KEY = "klevu-last-clicks-cat";
const MAX_COUNT = 20;
/**
 * Keeps track of last clicked products in store
 */
class LastClickedProducts {
    save() {
        if (KlevuConfig.getDefault().disableClickTracking) {
            return;
        }
        if (isBrowser() && window.localStorage) {
            KlevuStorage.setItem(LAST_CLICKED_STORAGE_KEY, JSON.stringify(this.clicks));
        }
    }
    saveCat() {
        if (KlevuConfig.getDefault().disableClickTracking) {
            return;
        }
        if (isBrowser() && window.sessionStorage && this.categoryCache) {
            KlevuStorage.setItem(LAST_CLICKED_CATEGORY_STORAGE_KEY, JSON.stringify(this.categoryCache), StorageType.SESSION);
        }
    }
    restore() {
        if (isBrowser() && window.localStorage) {
            const res = KlevuStorage.getItem(LAST_CLICKED_STORAGE_KEY);
            if (res) {
                this.clicks = JSON.parse(res);
            }
        }
        if (isBrowser() && window.localStorage) {
            const resCat = KlevuStorage.getItem(LAST_CLICKED_CATEGORY_STORAGE_KEY, StorageType.LOCAL);
            if (resCat) {
                this.categoryCache = JSON.parse(resCat);
            }
        }
    }
    constructor() {
        this.categoryCache = null;
        this.clicks = [];
        this.restore();
    }
    /**
     * Should be called when product is clicked
     *
     * @param productId
     */
    click(productId, product) {
        KlevuStorage.addKey(LAST_CLICKED_STORAGE_KEY);
        if (KlevuConfig.getDefault().disableClickTracking) {
            return;
        }
        const lastIndex = this.clicks.findIndex((ls) => ls.id === productId);
        if (lastIndex > -1) {
            this.clicks.splice(lastIndex, 1);
        }
        this.clicks.push({
            ts: new Date(),
            id: productId,
            product,
        });
        if (this.clicks.length > MAX_COUNT) {
            this.clicks = this.clicks.slice(MAX_COUNT * -1);
        }
        this.save();
        if (isBrowser()) {
            document.dispatchEvent(new CustomEvent(KlevuDomEvents.ClickEventSent, {
                detail: {
                    productId,
                    product,
                },
            }));
        }
    }
    /**
     * Gets last clicked products so that latest click is first item in array
     *
     * @param n
     * @returns
     */
    getLastClickedLatestsFirst(n = 10, filterDuplicates = false) {
        if (KlevuConfig.getDefault().disableClickTracking) {
            console.warn("Click tracking is disabled. Returning empty array.");
            return [];
        }
        let clicks = Array.from(this.clicks.map((i) => i.id)).reverse();
        if (filterDuplicates) {
            clicks = clicks.filter((item, index, self) => index === self.findIndex((t) => t === item));
        }
        return clicks.slice(0, n);
    }
    /**
     * Get last clicked products returning last clicked product first
     *
     * @param n amount of products to return
     * @returns
     */
    getProducts(n = 10) {
        if (KlevuConfig.getDefault().disableClickTracking) {
            console.warn("Click tracking is disabled. Returning empty array.");
            return [];
        }
        return Array.from(this.clicks.map((i) => i.product).filter(notEmpty))
            .reverse()
            .slice(0, n);
    }
    /**
     * Get id's for personlisation of category merchandising
     *
     * @param categoryPath any string that is used to cache results
     * @returns
     */
    getCategoryPersonalisationIds(categoryPath) {
        if (KlevuConfig.getDefault().disableClickTracking) {
            console.warn("Click tracking is disabled. Returning empty array.");
            return [];
        }
        const currentClicks = this.clicks;
        if (currentClicks.length < 3) {
            return [];
        }
        if (this.categoryCache) {
            if (new Date(this.categoryCache.cached).getTime() >
                new Date().getTime() - ONE_HOUR) {
                return this.categoryCache.ids;
            }
        }
        const itemsToTake = Math.floor(currentClicks.length / 3) * 3;
        const ids = Array.from(currentClicks)
            .reverse()
            .filter((item, index, self) => index === self.findIndex((t) => t.id === item.id))
            .slice(0, itemsToTake)
            .map((i) => i.id);
        this.categoryCache = {
            cached: new Date(),
            ids,
        };
        KlevuStorage.addKey(LAST_CLICKED_CATEGORY_STORAGE_KEY);
        this.saveCat();
        return ids;
    }
}
const KlevuLastClickedProducts = new LastClickedProducts();

/**
 * @category KlevuEvents
 */
class KlevuEvents {
    /**
     * Tell Klevu what products where bought by the user
     *
     * @param items Items user bought
     * @property amount count of bought products
     * @property product KlevuProduct that is being bought
     * @property variantId optional variantId that is being bought
     * @property override optional override any settings of sent data
     *
     */
    static buy({ user, items, }) {
        const userData = KlevuIpResolver.getDefault().getUserData();
        const data = {
            event: "order_purchase",
            event_version: "1.0.0",
            event_apikey: KlevuConfig.getDefault().apiKey,
            user_profile: Object.assign(Object.assign({}, user), { ip_address_v4: userData.ipv4, ip_address_v6: userData.ipv6, data_protection: KlevuConfig.getDefault().useConsent &&
                    KlevuConfig.getDefault().consentGiven, klevu_uuid: userData.uuid }),
            event_data: {
                items: items.map((i) => {
                    var _a, _b, _c, _d, _e, _f;
                    return (Object.assign({ currency: (_a = i.product.currency) !== null && _a !== void 0 ? _a : "USD", item_group_id: (_b = i.product.itemGroupId) !== null && _b !== void 0 ? _b : i.product.id, item_id: i.product.id, item_name: (_c = i.product.name) !== null && _c !== void 0 ? _c : "unknown", item_variant_id: (_d = i.variantId) !== null && _d !== void 0 ? _d : i.product.id, unit_price: parseFloat((_e = i.product.salePrice) !== null && _e !== void 0 ? _e : "0"), order_id: i.orderId, order_line_id: i.orderLineId, units: i.amount }, ((_f = i.override) !== null && _f !== void 0 ? _f : {})));
                }),
            },
        };
        KlevuEventV2CheckedOutProducts(data);
    }
    /**
     * When recommendation banner is shown in the page
     *
     * @param recommendation Metadata of what recommendation is shown
     * @param products List of all products that are shown
     * @param bannerInfo Information about the static banner that is shown
     * @param override Ability to override any analytical keys in low level
     */
    static recommendationView({ recommendationMetadata, products, bannerInfo, override = {}, }) {
        const userData = KlevuIpResolver.getDefault().getUserData();
        const data = {
            event: "view_recs_list",
            event_version: "1.0.0",
            event_apikey: KlevuConfig.getDefault().apiKey,
            user_profile: {
                sessionId: KlevuStorage.getItem(USER_SESSION_ID_STORAGE_KEY) || undefined,
                ip_address_v4: userData.ipv4,
                ip_address_v6: userData.ipv6,
                data_protection: KlevuConfig.getDefault().useConsent &&
                    KlevuConfig.getDefault().consentGiven,
                klevu_uuid: userData.uuid,
            },
            event_data: {
                list_id: recommendationMetadata.recsKey,
                list_logic: recommendationMetadata.logic,
                list_name: recommendationMetadata.title,
                action: recommendationMetadata.action,
                spot_id: recommendationMetadata.spotKey,
                spot_name: recommendationMetadata.spotName,
                segment_name: recommendationMetadata.segmentName || undefined,
                segment_id: recommendationMetadata.segmentKey || undefined,
                static_content: bannerInfo && [bannerInfo],
                items: products &&
                    products.map((p, index) => {
                        var _a, _b;
                        if (!p.id) {
                            throw new Error("Cannot send event without product id");
                        }
                        return {
                            index: index + 1,
                            item_id: p.id,
                            item_group_id: p.itemGroupId || p.id,
                            item_name: (_a = p.name) !== null && _a !== void 0 ? _a : "unknown",
                            item_variant_id: p.variantId || p.id,
                            price: (_b = p.price) !== null && _b !== void 0 ? _b : "0",
                            currency: p.currency,
                            item_brand: p.brand,
                            item_category: p.category,
                        };
                    }),
            },
        };
        KlevuEventV2([
            Object.assign(Object.assign({}, data), override),
        ]);
    }
    /**
     * When product has been clicked in the recommendation banner
     *
     * @param recommendationMetadata Metadata of what recommendation is clicked
     * @param bannerInfo Information about the static banner that is shown
     * @param product Which product is clicked in the list
     * @param productIndexInList What is the index of the product in the list. Starting from 1
     * @param override Ability to override any analytical keys in low level
     */
    static recommendationClick({ recommendationMetadata, product, bannerInfo, productIndexInList, variantId, override = {}, }) {
        var _a, _b;
        if (product) {
            KlevuLastClickedProducts.click(product.id, product);
        }
        const userData = KlevuIpResolver.getDefault().getUserData();
        const data = {
            event: "select_recs_list",
            event_version: "1.0.0",
            event_apikey: KlevuConfig.getDefault().apiKey,
            user_profile: {
                sessionId: KlevuStorage.getItem(USER_SESSION_ID_STORAGE_KEY) || undefined,
                ip_address_v4: userData.ipv4,
                ip_address_v6: userData.ipv6,
                data_protection: KlevuConfig.getDefault().useConsent &&
                    KlevuConfig.getDefault().consentGiven,
                klevu_uuid: userData.uuid,
            },
            event_data: {
                list_id: recommendationMetadata.recsKey,
                list_logic: recommendationMetadata.logic,
                list_name: recommendationMetadata.title,
                action: recommendationMetadata.action,
                spot_id: recommendationMetadata.spotKey,
                spot_name: recommendationMetadata.spotName,
                static_content: bannerInfo && [bannerInfo],
                segment_name: recommendationMetadata.segmentName || undefined,
                segment_id: recommendationMetadata.segmentKey || undefined,
                items: product && [
                    {
                        index: productIndexInList !== null && productIndexInList !== void 0 ? productIndexInList : 1,
                        item_id: product.id,
                        item_group_id: product.itemGroupId || product.id,
                        item_name: (_a = product.name) !== null && _a !== void 0 ? _a : "unknown",
                        item_variant_id: variantId || product.id,
                        price: (_b = product.salePrice) !== null && _b !== void 0 ? _b : "0",
                        currency: product.currency,
                        item_brand: product.brand,
                        item_category: product.category,
                    },
                ],
            },
        };
        KlevuEventV2([
            Object.assign(Object.assign({}, data), override),
        ]);
    }
    /**
     * When product is clicked. Do not use this for recommendations
     *
     * @param searchTerm
     * @param product
     */
    static searchProductClick({ product, searchTerm, variantId, activeFilters, tags, override = {}, }) {
        var _a, _b;
        if (!product.id) {
            throw new Error("Cannot send event without product id");
        }
        KlevuLastClickedProducts.click(product.id, product);
        const userData = KlevuIpResolver.getDefault().getUserData();
        const data = {
            klevu_apiKey: KlevuConfig.getDefault().apiKey,
            klevu_type: "clicked",
            klevu_keywords: searchTerm,
            klevu_productGroupId: product.itemGroupId || product.id,
            klevu_productId: product.id,
            klevu_productName: (_a = product.name) !== null && _a !== void 0 ? _a : "unknown",
            klevu_productUrl: (_b = product.url) !== null && _b !== void 0 ? _b : "",
            klevu_productVariantId: variantId || product.id,
            klevu_activeFilters: activeFilters,
            tags: tags || [],
            klevu_shopperIP_v4: userData.ipv4,
            klevu_shopperIP_v6: userData.ipv6,
            data_protection: KlevuConfig.getDefault().useConsent &&
                KlevuConfig.getDefault().consentGiven,
            klevu_uuid: userData.uuid,
        };
        KlevuEventV1ProductTracking(Object.assign(Object.assign({}, data), override));
    }
    /**
     * What user has last searched. This is important for Klevu to function
     * properly. Use `sendSearchEvent()` modifier with search query to send results
     *
     * @param term What was searched
     * @param totalResults Total number of results (can be found in result meta)
     * @param typeOfSearch Type of search used (can be found in result meta)
     * @param override Ability to override any analytical keys in low level
     */
    static search({ term, totalResults, typeOfSearch, activeFilters, tags, override = {}, }) {
        KlevuLastSearches.save(term);
        const userData = KlevuIpResolver.getDefault().getUserData();
        const data = {
            klevu_apiKey: KlevuConfig.getDefault().apiKey,
            klevu_term: term,
            klevu_totalResults: totalResults,
            klevu_typeOfQuery: typeOfSearch,
            klevu_activeFilters: activeFilters,
            klevu_shopperIP_v4: userData.ipv4,
            klevu_shopperIP_v6: userData.ipv6,
            tags: tags || [],
            data_protection: KlevuConfig.getDefault().useConsent &&
                KlevuConfig.getDefault().consentGiven,
            klevu_uuid: userData.uuid,
        };
        KlevuEventV1Search(Object.assign(Object.assign({}, data), override));
    }
    /**
     *
     * @param categoryTitle This is the name of the category being visited. For example, Stackable Rings. The name should not include parent categories.
     * @param klevuCategory This is the complete hierarchy of the category being visited. For example, Jewellery;Rings;Stackable Rings. Please note the use of a semicolon as the separator between a parent and a child category.
     * @param products Products in the view
     * @param pageStartsFrom Offset of the first product being shown on this page. For example, if you are displaying 30 products per page and if a customer is on the 2nd page, the value here should be 30. If on the 3rd page, it will be 60.
     * @param abTestId The AB test id currently running
     * @param abTestVariantId Id of AB test variant
     * @param activeFilters The string version of active filters applied to the query that got the products.
     * @param override Ability to override any analytical keys in low level
     */
    static categoryMerchandisingView({ categoryTitle, klevuCategory, products, pageStartsFrom, abTestId, abTestVariantId, activeFilters, override = {}, }) {
        const userData = KlevuIpResolver.getDefault().getUserData();
        const data = {
            klevu_apiKey: KlevuConfig.getDefault().apiKey,
            klevu_categoryName: categoryTitle,
            klevu_categoryPath: klevuCategory,
            klevu_productIds: products.map((p) => p.id).join(","),
            klevu_pageStartsFrom: pageStartsFrom,
            klevu_activeFilters: activeFilters,
            klevu_abTestId: abTestId,
            klevu_abTestVariantId: abTestVariantId,
            klevu_shopperIP_v4: userData.ipv4,
            klevu_shopperIP_v6: userData.ipv6,
            data_protection: KlevuConfig.getDefault().useConsent &&
                KlevuConfig.getDefault().consentGiven,
            klevu_uuid: userData.uuid,
        };
        KlevuEventV1CategoryView(Object.assign(Object.assign({}, data), override));
    }
    /**
     *
     * @param product Product clicked
     * @param categoryTitle This is the name of the category being visited. For example, Stackable Rings. The name should not include parent categories.
     * @param klevuCategory This is the complete hierarchy of the category being visited. For example, Jewellery;Rings;Stackable Rings. Please note the use of a semicolon as the separator between a parent and a child category.
     * @param variantId This is the child/variant ID of the clicked product. eg. 12345. For compound products with a parent and multiple child/variant products, this is the ID of the specific variant.
     * @param productPosition Position of the product on the category page when it was clicked. For example, the value would be 0 if it is the first product on the first page. The value will be 30, if it is the first product on the 2nd page with 30 products being displayed per page.
     * @param activeFilters The string version of active filters applied to the query that got the products.
     * @param override Ability to override any analytical keys in low level
     */
    static categoryMerchandisingProductClick({ product, categoryTitle, klevuCategory, variantId, productPosition, abTestId, abTestVariantId, activeFilters, override = {}, }) {
        if (!product.id) {
            throw new Error("Cannot send event without product id");
        }
        KlevuLastClickedProducts.click(product.id, product);
        const userData = KlevuIpResolver.getDefault().getUserData();
        const data = {
            klevu_apiKey: KlevuConfig.getDefault().apiKey,
            klevu_categoryName: categoryTitle,
            klevu_productGroupId: product.itemGroupId || product.id,
            klevu_productVariantId: variantId || product.id,
            klevu_categoryPath: klevuCategory,
            klevu_productId: product.id,
            klevu_productName: product.name,
            klevu_productUrl: product.url,
            klevu_salePrice: product.salePrice,
            klevu_productSku: product.sku,
            klevu_productPosition: productPosition,
            klevu_abTestId: abTestId,
            klevu_abTestVariantId: abTestVariantId,
            klevu_activeFilters: activeFilters,
            klevu_shopperIP_v4: userData.ipv4,
            klevu_shopperIP_v6: userData.ipv6,
            data_protection: KlevuConfig.getDefault().useConsent &&
                KlevuConfig.getDefault().consentGiven,
            klevu_uuid: userData.uuid,
        };
        KlevuEventV1CategoryProductClick(Object.assign(Object.assign({}, data), override));
    }
    /**
     * When user clicks on the banner that is in quicksearch or on search landing page
     */
    static imageBannerClick({ term, bannerId, bannerName, imageUrl, targetUrl, override = {}, }) {
        const data = {
            klevu_apiKey: KlevuConfig.getDefault().apiKey,
            type: "banner",
            klevu_request: "click",
            klevu_term: term,
            klevu_bannerId: bannerId,
            klevu_bannerName: bannerName,
            klevu_image: imageUrl,
            klevu_target: targetUrl,
        };
        KlevuEventV1BannerClick(Object.assign(Object.assign({}, data), override));
    }
}

var __awaiter$6 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
/**
 *
 * @category Modifier
 * @param term Search term from input
 * @param id id of request. Response is under this is. Has to be unique across single query. Default is 'search'
 * @param options
 * @returns
 */
function applyFilters(filters) {
    const query = {
        applyFilters: {
            filters,
        },
    };
    return {
        klevuModifierId: "applyFilters",
        modifyAfter: (queries) => __awaiter$6(this, void 0, void 0, function* () {
            const copy = Array.from(queries);
            if (filters.length == 0) {
                return copy;
            }
            for (const q of copy) {
                const filters = Object.assign(Object.assign({}, q.filters), { applyFilters: query.applyFilters });
                q.filters = filters;
            }
            return copy;
        }),
    };
}

/**
 * Apply filters to query based on Filter Manager
 *
 * @category Modifier
 * @param manager
 * @param options
 * @returns
 */
function applyFilterWithManager(manager) {
    return applyFilters(manager.toApplyFilters());
}

/**
 * build a string|undefined from active filters in format that is required by Klevu API
 *
 * @param result the api result object
 */
function extractActiveFilters(result) {
    var _a;
    let selectedFiltersStr = "";
    let isAnyFilterSelected = false;
    if (!result.filters || result.filters.length === 0) {
        return undefined;
    }
    (_a = result.filters) === null || _a === void 0 ? void 0 : _a.forEach((filter) => {
        if (filter.type === KlevuFilterType.Slider) {
            if (!filter.start || !filter.end) {
                return;
            }
            if (filter.start != filter.min || filter.end != filter.max) {
                if (isAnyFilterSelected) {
                    selectedFiltersStr += ";;";
                }
                isAnyFilterSelected = true;
                selectedFiltersStr +=
                    filter.key + ":" + filter.start + " - " + filter.end;
            }
        }
        else {
            filter.options.forEach((option) => {
                if (!option.selected) {
                    return;
                }
                if (isAnyFilterSelected) {
                    selectedFiltersStr += ";;";
                }
                isAnyFilterSelected = true;
                selectedFiltersStr += filter.key + ":" + option.name;
            });
        }
    });
    return isAnyFilterSelected ? selectedFiltersStr : undefined;
}

var __awaiter$5 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
/**
 * Enable personlisation to the query
 *
 * @category Modifier
 * @param options
 * @returns
 */
function personalisation(options) {
    return {
        klevuModifierId: "personalisation",
        modifyAfter: (queries, klevuFunc) => __awaiter$5(this, void 0, void 0, function* () {
            var _a, _b;
            const copy = Array.from(queries);
            for (const q of queries) {
                if (!q.settings) {
                    q.settings = {};
                }
                q.settings.personalisation = {
                    enablePersonalisation: true,
                    fields: options === null || options === void 0 ? void 0 : options.fields,
                };
                let records = [];
                if ((options === null || options === void 0 ? void 0 : options.lastClickedProductIds) || (options === null || options === void 0 ? void 0 : options.lastClickedItemIds)) {
                    const ids = (_a = (options.lastClickedItemIds || options.lastClickedProductIds)) !== null && _a !== void 0 ? _a : [];
                    records = ids.map((pId) => ({
                        id: pId,
                    }));
                }
                else if (klevuFunc.klevuFunctionId === "categoryMerchandising" &&
                    ((_b = klevuFunc.params) === null || _b === void 0 ? void 0 : _b.category)) {
                    const { category } = klevuFunc.params;
                    records = KlevuLastClickedProducts.getCategoryPersonalisationIds(category).map((id) => ({ id }));
                }
                else {
                    records = KlevuLastClickedProducts.getLastClickedLatestsFirst(10, true).map((id) => ({ id }));
                }
                if (records.length > 0) {
                    q.settings.context = {
                        recentObjects: [
                            {
                                typeOfRecord: KlevuTypeOfRecord.Product,
                                records,
                            },
                        ],
                    };
                }
            }
            return copy;
        }),
    };
}

var __awaiter$4 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
/**
 *
 * @param id Id of query response to find
 * @param response Raw API response from server
 * @param product Id of product to find
 * @param languageCode Language code to process in
 * @returns
 */
function getAnnotationsForProduct(response, productId, languageCode) {
    var _a;
    return __awaiter$4(this, void 0, void 0, function* () {
        const prod = (_a = response.records) === null || _a === void 0 ? void 0 : _a.find((s) => s.id === productId);
        if (!prod) {
            return undefined;
        }
        const paramaters = {
            query: response.meta.searchedTerm,
            title: prod.name,
            category: prod.category,
            languageCode: languageCode,
        };
        const url = "https://nlp-services.ksearchnet.com/" +
            KlevuConfig.getDefault().apiKey +
            "/annotations" +
            objectToQueryParameters(paramaters);
        return yield get(url);
    });
}

function KlevuGetBannersByType(banners, searchType, termOrCategory) {
    const dateFiltered = filterBannersByDate(banners);
    const typeFiltered = dateFiltered.filter((banner) => {
        switch (searchType) {
            case "landingpage": {
                return banner.showOnLandingPage;
            }
            case "quicksearch": {
                return banner.showOnQuickSearch;
            }
            case "merchandising": {
                return banner.showOnCategoryPage;
            }
        }
    });
    return filterBannersByTerm(typeFiltered, termOrCategory);
}
function filterBannersByTerm(banners, term) {
    return banners.filter((banner) => banner.showForTerms === null || banner.showForTerms.includes(term));
}
function filterBannersByDate(banners, date = new Date()) {
    return banners.filter((banner) => {
        const startDate = bannerDateToDate(banner.startDate);
        if (banner.endDate === "") {
            return startDate <= date;
        }
        const endDate = bannerDateToDate(banner.endDate, true);
        return startDate <= date && endDate >= date;
    });
}
function bannerDateToDate(date, end) {
    const [year, month, day] = date.split("/");
    const jsDate = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
    if (end) {
        jsDate.setHours(23, 59, 59);
    }
    return jsDate;
}

var __awaiter$3 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
function getBanners(responseObject, searchType) {
    var _a, _b;
    return __awaiter$3(this, void 0, void 0, function* () {
        if (!["search", "categoryMerchandising"].includes(responseObject.func.klevuFunctionId)) {
            return [];
        }
        const settings = yield KlevuKMCSettings();
        if (!settings.banner) {
            return [];
        }
        switch (responseObject.func.klevuFunctionId) {
            case "search": {
                if (!searchType) {
                    throw new Error("Search type (landingpage|quicksearch) is required for search query banners");
                }
                const searchTerm = (_a = responseObject.func.params) === null || _a === void 0 ? void 0 : _a.term;
                if (!searchTerm) {
                    throw new Error("Search term is required for search query banners");
                }
                return KlevuGetBannersByType(settings.banner.klevu_banner, searchType, searchTerm);
            }
            case "categoryMerchandising": {
                const category = (_b = responseObject.func.params) === null || _b === void 0 ? void 0 : _b.category;
                if (!category) {
                    return [];
                }
                return KlevuGetBannersByType(settings.banner.klevu_banner, "merchandising", category);
            }
        }
        throw new Error("Couldn't find banners for this query. Unknown query type.");
    });
}

var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
function getRedirects(term) {
    return __awaiter$2(this, void 0, void 0, function* () {
        const settings = yield KlevuKMCSettings();
        if (!settings.maps) {
            return [];
        }
        return settings.maps.klevu_keywordUrlMap.filter((map) => map.keywords.some((k) => k === term));
    });
}

var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __classPrivateFieldGet$1 = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _KlevuResponseQueryObject_instances, _KlevuResponseQueryObject_initRedirects, _KlevuResponseQueryObject_initEventFunctions;
/**
 * Result object for each query. A storage for results. Can be used to fetch more data, send events etc.
 */
class KlevuResponseQueryObject {
    constructor(responseObject, query, func) {
        _KlevuResponseQueryObject_instances.add(this);
        /**
         * Hooks that can be used to listen for events
         */
        this.hooks = [];
        this.responseObject = responseObject;
        this.query = query;
        this.func = func;
        __classPrivateFieldGet$1(this, _KlevuResponseQueryObject_instances, "m", _KlevuResponseQueryObject_initEventFunctions).call(this);
        __classPrivateFieldGet$1(this, _KlevuResponseQueryObject_instances, "m", _KlevuResponseQueryObject_initRedirects).call(this);
    }
    /**
     * All filters related to this query
     */
    get filters() {
        return this.query.filters;
    }
    /**
     * Id if the query
     */
    get id() {
        return this.query.id;
    }
    /**
     * Meta data of the query
     */
    get meta() {
        return this.query.meta;
    }
    /**
     * Records of the query
     */
    get records() {
        return this.query.records;
    }
    /**
     * Special parameters that are saved to query
     */
    get functionParams() {
        return this.func.params;
    }
    /**
     * Fetches page of results. If pageIndex is not defined it will fetch next page.
     *
     * @param params
     * @returns
     */
    getPage(params) {
        var _a, _b, _c, _d;
        return __awaiter$1(this, void 0, void 0, function* () {
            const newFunc = Object.assign({}, this.func);
            const prevQueryResponse = this.query;
            if (!newFunc.queries) {
                return undefined;
            }
            for (let i = 0; i < newFunc.queries.length; i++) {
                const prevQuery = newFunc.queries[i];
                if (!prevQuery.settings) {
                    prevQuery.settings = {};
                }
                if ((params === null || params === void 0 ? void 0 : params.pageIndex) !== undefined) {
                    prevQuery.settings.offset =
                        prevQueryResponse.meta.noOfResults * params.pageIndex;
                }
                else {
                    prevQuery.settings.offset =
                        prevQueryResponse.meta.noOfResults + prevQueryResponse.meta.offset;
                }
                prevQuery.settings.limit = (_c = (_a = params === null || params === void 0 ? void 0 : params.limit) !== null && _a !== void 0 ? _a : (_b = prevQuery.settings) === null || _b === void 0 ? void 0 : _b.limit) !== null && _c !== void 0 ? _c : 5;
                newFunc.queries[i] = prevQuery;
            }
            // add previous filters with manager
            if (params === null || params === void 0 ? void 0 : params.filterManager) {
                if (!newFunc.modifiers) {
                    newFunc.modifiers = [];
                }
                newFunc.modifiers.push(applyFilterWithManager(params.filterManager));
            }
            newFunc.previousResultRecords = [
                ...((_d = this.func.previousResultRecords) !== null && _d !== void 0 ? _d : []),
                ...prevQueryResponse.records,
            ];
            return yield KlevuFetch(removeListFilters(newFunc, prevQueryResponse));
        });
    }
    /**
     *
     * @returns true if there are more pages to fetch
     */
    hasNextPage() {
        return (this.query.meta.totalResultsFound >
            this.query.meta.offset + this.query.meta.noOfResults);
    }
    /**
     *
     * @returns total number of pages
     */
    getTotalPages() {
        return Math.ceil(this.query.meta.totalResultsFound / this.query.meta.offset);
    }
    annotationsById(productId, languageCode) {
        return getAnnotationsForProduct(this.query, productId, languageCode);
    }
    /**
     * @returns List of banners that were received for this query
     * @param params in case of search query you need to specify location of search
     */
    getBanners(params = {}) {
        return __awaiter$1(this, void 0, void 0, function* () {
            return getBanners(this, params.searchType);
        });
    }
    /**
     * @returns List of params used in the query and the metadata that was generated during
     * the query. This is useful for example to fetching KMC metadata that was received
     * for recommendations query.
     */
    getQueryParameters() {
        return this.func.params;
    }
}
_KlevuResponseQueryObject_instances = new WeakSet(), _KlevuResponseQueryObject_initRedirects = function _KlevuResponseQueryObject_initRedirects() {
    if (this.func.klevuFunctionId === "search") {
        this.getRedirects = () => {
            var _a;
            if (!((_a = this.func.params) === null || _a === void 0 ? void 0 : _a.term)) {
                return Promise.resolve([]);
            }
            return getRedirects(this.func.params.term);
        };
    }
}, _KlevuResponseQueryObject_initEventFunctions = function _KlevuResponseQueryObject_initEventFunctions() {
    var _a, _b, _c;
    switch ((_a = this.func) === null || _a === void 0 ? void 0 : _a.klevuFunctionId) {
        case "search": {
            this.searchClickEvent = function ({ productId, variantId, autoSendViewEvent = true, override, }) {
                var _a, _b, _c;
                if (!this.func) {
                    return;
                }
                if (autoSendViewEvent && !((_a = this.func.params) === null || _a === void 0 ? void 0 : _a.searchSendEventSent)) {
                    KlevuEvents.search({
                        term: this.query.meta.searchedTerm,
                        totalResults: this.query.meta.noOfResults,
                        typeOfSearch: this.query.meta.typeOfSearch,
                        activeFilters: extractActiveFilters(this.query),
                        override,
                        tags: this.query.meta.tags,
                    });
                    if (!this.func.params) {
                        this.func.params = {};
                    }
                    this.func.params.searchSendEventSent = true;
                }
                const record = [
                    ...this.query.records,
                    ...((_b = this.func.previousResultRecords) !== null && _b !== void 0 ? _b : []),
                ].find((r) => r.id === productId);
                if (!record) {
                    throw new Error(`KlevuEvents: Given "${productId}" doesn't exists in this.querys`);
                }
                KlevuEvents.searchProductClick({
                    product: record,
                    searchTerm: this.query.meta.searchedTerm,
                    variantId,
                    tags: this.query.meta.tags,
                });
                for (const hook of (_c = this.hooks) !== null && _c !== void 0 ? _c : []) {
                    hook({ type: "search", productId, variantId });
                }
            };
            break;
        }
        case "categoryMerchandising": {
            this.categoryMerchandisingClickEvent = function ({ productId, categoryTitle, variantId, override, }) {
                var _a, _b, _c, _d, _e, _f;
                if (!this.func) {
                    return;
                }
                const record = [
                    ...this.query.records,
                    ...((_a = this.func.previousResultRecords) !== null && _a !== void 0 ? _a : []),
                ].find((r) => r.id === productId);
                if (!record) {
                    throw new Error(`KlevuEvents: Given "${productId}" doesn't exists in this.querys`);
                }
                const index = this.query.records.findIndex((r) => r.id === productId);
                const q = (_b = this.func.queries) === null || _b === void 0 ? void 0 : _b.find((q) => { var _a, _b; return Boolean((_b = (_a = q.settings) === null || _a === void 0 ? void 0 : _a.query) === null || _b === void 0 ? void 0 : _b.categoryPath); });
                let abTestId, abTestVariantId;
                if (!this.func.params) {
                    this.func.params = {};
                }
                if (this.func.params.abtest) {
                    abTestId = this.func.params.abtest.abTestId;
                    abTestVariantId = this.func.params.abtest.abTestVariantId;
                }
                KlevuEvents.categoryMerchandisingProductClick({
                    product: record,
                    categoryTitle,
                    klevuCategory: (_e = (_d = (_c = q === null || q === void 0 ? void 0 : q.settings) === null || _c === void 0 ? void 0 : _c.query) === null || _d === void 0 ? void 0 : _d.categoryPath) !== null && _e !== void 0 ? _e : "unknown",
                    variantId,
                    productPosition: (this.query.meta.offset || 0) + index + 1,
                    abTestId,
                    abTestVariantId,
                    activeFilters: extractActiveFilters(this.query),
                    override,
                });
                for (const hook of (_f = this.hooks) !== null && _f !== void 0 ? _f : []) {
                    hook({ type: "categoryMerchandising", productId, variantId });
                }
            };
            break;
        }
        case "kmcRecommendation": {
            if (!((_b = this.func.params) === null || _b === void 0 ? void 0 : _b.kmcConfig)) {
                break;
            }
            const config = (_c = this.func.params) === null || _c === void 0 ? void 0 : _c.kmcConfig;
            if (config.metadata.action === "HIDE_RECOMMENDATION") {
                break;
            }
            if (config.metadata.action === "STATIC_CONTENT") {
                if (!config.staticContent) {
                    break;
                }
                this.recommendationBannerClickEvent = function ({ resolution }) {
                    var _a;
                    if (!config.staticContent || config.staticContent.length === 0) {
                        return;
                    }
                    const image = (_a = config.staticContent[0].image.find((image) => image.resolution === resolution)) !== null && _a !== void 0 ? _a : config.staticContent[0].image[0];
                    if (!image) {
                        return;
                    }
                    KlevuEvents.recommendationClick({
                        recommendationMetadata: config.metadata,
                        bannerInfo: {
                            resolution,
                            index: 1,
                            banner_alt_tag: image.altTag,
                            banner_image_url: image.url,
                            content_type: "image",
                        },
                    });
                };
                break;
            }
            this.recommendationClickEvent = function ({ productId, variantId, override, }) {
                var _a, _b;
                if (!this.func) {
                    return;
                }
                const record = [
                    ...this.query.records,
                    ...((_a = this.func.previousResultRecords) !== null && _a !== void 0 ? _a : []),
                ].find((r) => r.id === productId);
                if (!record) {
                    throw new Error(`KlevuEvents: Given "${productId}" doesn't exists in this.querys`);
                }
                if (!config) {
                    throw new Error("KlevuEvents: Recommendation kmcConfig not available");
                }
                const index = this.query.records.findIndex((r) => r.id === productId);
                KlevuEvents.recommendationClick({
                    recommendationMetadata: config.metadata,
                    product: record,
                    productIndexInList: index + 1,
                    variantId,
                    override,
                });
                for (const hook of (_b = this.hooks) !== null && _b !== void 0 ? _b : []) {
                    hook({ type: "recommendation", productId, variantId });
                }
            };
        }
    }
};

var __classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _KlevuResponseObject_instances, _KlevuResponseObject_functions, _KlevuResponseObject_queryObjects, _KlevuResponseObject_buildQueryObjects;
/**
 * This class is used to access the response data from Klevu API
 * It builds up the state of the result and it can be used to do various things with the data
 */
class KlevuResponseObject {
    constructor(response, functions, options, checkProcessedFunctions) {
        _KlevuResponseObject_instances.add(this);
        _KlevuResponseObject_functions.set(this, void 0);
        _KlevuResponseObject_queryObjects.set(this, {});
        this.apiResponse = response;
        __classPrivateFieldSet(this, _KlevuResponseObject_functions, functions, "f");
        if (checkProcessedFunctions &&
            this.packProcessedFunctionsToString() !== checkProcessedFunctions) {
            throw new Error("Processed functions are not the same as on the backend");
        }
        __classPrivateFieldGet(this, _KlevuResponseObject_instances, "m", _KlevuResponseObject_buildQueryObjects).call(this);
        for (const f of functions) {
            if (f.modifiers) {
                for (const modifier of f.modifiers) {
                    if (!modifier.onResult) {
                        continue;
                    }
                    if (!(options === null || options === void 0 ? void 0 : options.params.isSSR) ||
                        (options.params.isSSR && !modifier.ssrOnResultFE)) {
                        modifier.onResult(this, f);
                    }
                    else if ((options === null || options === void 0 ? void 0 : options.params.FEHydrate) && modifier.ssrOnResultFE) {
                        modifier.onResult(this, f);
                    }
                }
            }
        }
    }
    /**
     * Get suggestions by id
     *
     * @param id
     * @returns
     */
    suggestionsById(id) {
        var _a;
        return (_a = this.apiResponse.suggestionResults) === null || _a === void 0 ? void 0 : _a.find((q) => q.id === id);
    }
    /**
     * Get query results by id
     * @param id query id used
     * @returns
     */
    queriesById(id) {
        if (!__classPrivateFieldGet(this, _KlevuResponseObject_queryObjects, "f")[id]) {
            throw new Error(`Query with id ${id} not found`);
        }
        return __classPrivateFieldGet(this, _KlevuResponseObject_queryObjects, "f")[id];
    }
    /**
     * Check if query exists. This should be used as queriesById can throw an error
     *
     * @param id query id used
     * @returns
     */
    queryExists(id) {
        return !!__classPrivateFieldGet(this, _KlevuResponseObject_queryObjects, "f")[id];
    }
    /**
     *
     * @returns String that can be used to compare if the same functions were used to create this response
     */
    packProcessedFunctionsToString() {
        return __classPrivateFieldGet(this, _KlevuResponseObject_functions, "f")
            .map((f) => {
            var _a, _b;
            return `${f.klevuFunctionId},${(_a = f.queries) === null || _a === void 0 ? void 0 : _a.map((q) => q.id)},${(_b = f.modifiers) === null || _b === void 0 ? void 0 : _b.map((m) => m.klevuModifierId)}`;
        })
            .join(";");
    }
}
_KlevuResponseObject_functions = new WeakMap(), _KlevuResponseObject_queryObjects = new WeakMap(), _KlevuResponseObject_instances = new WeakSet(), _KlevuResponseObject_buildQueryObjects = function _KlevuResponseObject_buildQueryObjects() {
    var _a;
    for (const q of (_a = this.apiResponse.queryResults) !== null && _a !== void 0 ? _a : []) {
        const func = __classPrivateFieldGet(this, _KlevuResponseObject_functions, "f").find((f) => { var _a; return (_a = f.queries) === null || _a === void 0 ? void 0 : _a.some((qu) => q.id == qu.id || q.id == `${qu.id}-fallback`); });
        if (func) {
            __classPrivateFieldGet(this, _KlevuResponseObject_queryObjects, "f")[q.id] = new KlevuResponseQueryObject(this, q, func);
        }
    }
};

var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
const klevuFetchCache = new KlevuFetchCache();
class KlevuFetchOption {
    constructor(params = {}) {
        this.params = params;
    }
}
/**
 * Function that makes query to KlevuBackend. It can take amount of queries.
 *
 * @category KlevuFetch
 * @param functions list of functions to execute
 * @returns Tools to operate results
 */
function KlevuFetch(...functionPromises) {
    var _a, _b, _c, _d, _e;
    return __awaiter(this, void 0, void 0, function* () {
        if (functionPromises.length < 1) {
            throw new Error("At least one fetch function should be provided to fetch.");
        }
        const option = functionPromises.find((f) => f instanceof KlevuFetchOption);
        const functionPromisesWithoutOptions = functionPromises.filter((f) => !(f instanceof KlevuFetchOption));
        const functions = yield Promise.all(functionPromisesWithoutOptions);
        const { recordQueries, suggestionQueries } = yield cleanAndProcessFunctions(functions);
        const withOverride = functions.find((f) => Boolean(f.configOverride));
        const payload = {
            context: {
                apiKeys: [
                    (_b = (_a = withOverride === null || withOverride === void 0 ? void 0 : withOverride.configOverride) === null || _a === void 0 ? void 0 : _a.apiKey) !== null && _b !== void 0 ? _b : KlevuConfig.getDefault().apiKey,
                ],
            },
            recordQueries: recordQueries.length > 0 ? recordQueries : undefined,
            suggestions: suggestionQueries.length > 0 ? suggestionQueries : undefined,
        };
        const cached = klevuFetchCache.check(payload);
        let response;
        const withoutSkip = recordQueries.filter((q) => q.typeOfRequest !== KlevuTypeOfRequest.Skip);
        if (withoutSkip.length > 0 || suggestionQueries.length > 0) {
            if (cached) {
                response = cached;
            }
            else {
                const res = yield post((_d = (_c = withOverride === null || withOverride === void 0 ? void 0 : withOverride.configOverride) === null || _c === void 0 ? void 0 : _c.url) !== null && _d !== void 0 ? _d : KlevuConfig.getDefault().url, payload);
                if (!res) {
                    throw new Error("Couldn't fetch data");
                }
                response = res;
                if (((_e = res.meta) === null || _e === void 0 ? void 0 : _e.responseCode) == 200) {
                    klevuFetchCache.cache(payload, response);
                }
            }
        }
        return new KlevuResponseObject(response !== null && response !== void 0 ? response : {
            meta: {
                qTime: 0,
                responseCode: 204,
            },
            queryResults: recordQueries.map((r) => ({
                id: r.id,
                meta: {},
                records: [],
            })),
            suggestionResults: [],
        }, functions, option);
    });
}
function cleanAndProcessFunctions(functions) {
    return __awaiter(this, void 0, void 0, function* () {
        const recordQueries = [];
        const suggestionQueries = [];
        for (const f of functions) {
            if (f.queries) {
                let qs = [...f.queries];
                if (f.modifiers) {
                    for (const modifier of f.modifiers) {
                        if (modifier.modifyAfter) {
                            qs = yield modifier.modifyAfter(qs, f);
                        }
                    }
                }
                recordQueries.push(...qs);
            }
            if (f.suggestions) {
                suggestionQueries.push(...f.suggestions);
            }
        }
        // Check for duplicate id's
        for (const query of recordQueries) {
            if (recordQueries.filter((q) => q.id === query.id).length !== 1) {
                throw new Error("Duplicate ids in request. Please provider unique ids for requests");
            }
        }
        return {
            recordQueries,
            suggestionQueries,
        };
    });
}
/**
 * Removes list filters from query
 *
 * @param f
 * @param prevQueryResult
 * @returns
 */
function removeListFilters(f, prevQueryResult) {
    var _a;
    f.queries = (_a = f.queries) === null || _a === void 0 ? void 0 : _a.map((q) => {
        var _a, _b;
        if ((_a = q.filters) === null || _a === void 0 ? void 0 : _a.filtersToReturn) {
            (_b = q.filters) === null || _b === void 0 ? true : delete _b.filtersToReturn;
        }
        return q;
    });
    if (f.modifiers) {
        const index = f.modifiers.findIndex((m) => m.klevuModifierId == "listfilters");
        if (index > -1) {
            f.modifiers.splice(index, 1);
        }
        f.modifiers.push(injectFilterResult(prevQueryResult));
    }
    return f;
}

export { KlevuTypeOfRequest as K, KlevuResponseObject as a, KlevuFetchOption as b, KlevuFetch as c, applyFilterWithManager as d, KlevuEvents as e, extractActiveFilters as f, KlevuTypeOfRecord as g, KlevuFilterOrder as h, KlevuLastClickedProducts as i, personalisation as p };

//# sourceMappingURL=klevuFetch.js.map