export const randomID = (prepend, length = 5) => prepend +
    Math.random()
        .toString(36)
        .substring(2, 2 + length);
export function isArray(value) {
    return Array.isArray(value);
}
export function isEmptyString(str) {
    return str.trim() === '';
}
export function removeDuplicates(arr, predicate) {
    return [
        ...arr
            .reduce((map, item) => {
            const key = predicate(item);
            map.has(key) || map.set(key, item);
            return map;
        }, new Map())
            .values(),
    ];
}
function encodedBtoa(stringToEncode) {
    return btoa(encodeURI(stringToEncode));
}
export function omit(key, obj) {
    const { [key]: _omitted, ...rest } = obj;
    return rest;
}
export function getObjectHash(obj) {
    return encodedBtoa(JSON.stringify(obj));
}
const doNotTrackValues = new Set(['1', 1, 'yes', true]);
// TODO KIT-2844
/**
 * Logic copied from coveo.analytics.
 *
 * @deprecated V4 - Starting with Event Protocol, Coveo will no longer respect the DNT standard.
 * Instead, we will provide implementers with documentation on privacy best-practices, letting
 * them decide which standards to respect.
 * For more context behind the decision, see: https://coveord.atlassian.net/browse/LENS-1502
 */
export function doNotTrack() {
    if (typeof navigator === 'undefined' || typeof window === 'undefined') {
        return false;
    }
    // biome-ignore lint/suspicious/noExplicitAny: <>
    const nav = navigator;
    // biome-ignore lint/suspicious/noExplicitAny: <>
    const win = window;
    return [
        nav.globalPrivacyControl,
        nav.doNotTrack,
        nav.msDoNotTrack,
        win.doNotTrack,
    ].some((value) => doNotTrackValues.has(value));
}
export function fromEntries(values) {
    const newObject = {};
    for (const [key, value] of values) {
        newObject[key] = value;
    }
    return newObject;
}
export function resetTimeout(
// biome-ignore lint/suspicious/noExplicitAny: <>
callback, timeoutId, ms) {
    clearTimeout(timeoutId);
    return setTimeout(callback, ms);
}
export function mapObject(obj, predicate) {
    return Object.fromEntries(Object.entries(obj).map(([key, value]) => [
        key,
        predicate(value, key),
    ]));
}
export function filterObject(obj, predicate) {
    return Object.fromEntries(Object.entries(obj).filter(([key, value]) => predicate(value, key)));
}
// TODO: Could eventually be replaced with `structuredClone`.
// However, this is not compatible with salesforce locker service.
export function clone(value) {
    if (typeof value !== 'object') {
        return value;
    }
    if (!value) {
        return value;
    }
    // JSON parse/stringify can fail in some cases (ie: recursive objects)
    // add defensive code to prevent the whole app from crashing
    try {
        return JSON.parse(JSON.stringify(value));
    }
    catch (_) {
        return value;
    }
}
function createDeferredPromise() {
    let resolve = null;
    let reject = null;
    const promise = new Promise((_resolve, _reject) => {
        resolve = _resolve;
        reject = _reject;
    });
    return { promise, resolve: resolve, reject: reject };
}
export function createWaitForActionMiddleware(isDesiredAction) {
    const { promise, resolve } = createDeferredPromise();
    const middleware = () => (next) => (action) => {
        next(action);
        if (isDesiredAction(action)) {
            resolve(action);
        }
    };
    return { promise, middleware };
}
function isRecommendationActionPayload(action) {
    if (action === null || action === undefined) {
        return false;
    }
    if (typeof action === 'object' && 'meta' in action) {
        return (action.meta
            ?.arg?.slotId !== undefined);
    }
    return false;
}
export function createWaitForActionMiddlewareForRecommendation(isDesiredAction, memo) {
    const { promise, resolve } = createDeferredPromise();
    let hasBeenResolved = false;
    const hasSlotBeenProcessed = (slotId) => memo.has(slotId);
    const middleware = () => (next) => (action) => {
        next(action);
        if (isDesiredAction(action) &&
            !hasBeenResolved &&
            isRecommendationActionPayload(action) &&
            !hasSlotBeenProcessed(action.meta.arg.slotId)) {
            hasBeenResolved = true;
            memo.add(action.meta.arg.slotId);
            resolve(action);
        }
    };
    return { promise, middleware };
}
