"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.debounce = exports.approxEqual = void 0;
exports.memo = memo;
exports.notUndefined = notUndefined;
function memo(getDeps, fn, opts) {
    var _a;
    let deps = (_a = opts.initialDeps) !== null && _a !== void 0 ? _a : [];
    let result;
    function memoizedFunction() {
        var _a, _b, _c, _d;
        let depTime;
        if (opts.key && ((_a = opts.debug) === null || _a === void 0 ? void 0 : _a.call(opts)))
            depTime = Date.now();
        const newDeps = getDeps();
        const depsChanged = newDeps.length !== deps.length ||
            newDeps.some((dep, index) => deps[index] !== dep);
        if (!depsChanged) {
            return result;
        }
        deps = newDeps;
        let resultTime;
        if (opts.key && ((_b = opts.debug) === null || _b === void 0 ? void 0 : _b.call(opts)))
            resultTime = Date.now();
        result = fn(...newDeps);
        if (opts.key && ((_c = opts.debug) === null || _c === void 0 ? void 0 : _c.call(opts))) {
            const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;
            const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;
            const resultFpsPercentage = resultEndTime / 16;
            const pad = (str, num) => {
                str = String(str);
                while (str.length < num) {
                    str = ` ${str}`;
                }
                return str;
            };
            console.info(`%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`, `
            font-size: .6rem;
            font-weight: bold;
            color: hsl(${Math.max(0, Math.min(120 - 120 * resultFpsPercentage, 120))}deg 100% 31%);`, opts === null || opts === void 0 ? void 0 : opts.key);
        }
        (_d = opts === null || opts === void 0 ? void 0 : opts.onChange) === null || _d === void 0 ? void 0 : _d.call(opts, result);
        return result;
    }
    // Attach updateDeps to the function itself
    memoizedFunction.updateDeps = (newDeps) => {
        deps = newDeps;
    };
    return memoizedFunction;
}
function notUndefined(value, msg) {
    if (value === undefined) {
        throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`);
    }
    else {
        return value;
    }
}
const approxEqual = (a, b) => Math.abs(a - b) < 1.01;
exports.approxEqual = approxEqual;
const debounce = (targetWindow, fn, ms) => {
    let timeoutId;
    return function (...args) {
        targetWindow.clearTimeout(timeoutId);
        timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms);
    };
};
exports.debounce = debounce;
