"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.pluralize = exports.extend = exports.wrap = exports.batchify = exports.cachify = exports.absolutizeUrl = exports.removeUndefinedProps = exports.toUriEncoding = exports.toUnAnchoredUri = exports.toString = exports.toJSON = exports.sleep = exports.jwtDecode = exports.shortid = exports.guid = exports.getEnvValue = void 0;
const buffer_1 = require("buffer");
const types = __importStar(require("./types"));
function getEnvValue(name, type) {
    if (!process)
        return undefined;
    const value = process.env[`APPLITOOLS_${name}`];
    if (value === undefined || value === 'null')
        return undefined;
    if (type === 'boolean')
        return ['true', true, '1', 1].includes(value);
    if (type === 'number')
        return Number(value);
    return value;
}
exports.getEnvValue = getEnvValue;
function guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
        const r = (Math.random() * 16) | 0;
        const v = c === 'x' ? r : (r & 0x3) | 0x8;
        return v.toString(16);
    });
}
exports.guid = guid;
function shortid() {
    return 'xxx'.replace(/[x]/g, () => {
        const r = (Math.random() * 36) | 0;
        return r.toString(36);
    });
}
exports.shortid = shortid;
function jwtDecode(token) {
    let payloadSeg = token.split('.')[1];
    payloadSeg += new Array(5 - (payloadSeg.length % 4)).join('=');
    payloadSeg = payloadSeg.replace(/-/g, '+').replace(/_/g, '/');
    return JSON.parse(buffer_1.Buffer.from(payloadSeg, 'base64').toString());
}
exports.jwtDecode = jwtDecode;
function sleep(ms) {
    if (types.isNumber(ms)) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}
exports.sleep = sleep;
function toJSON(object, props) {
    if (!types.isObject(object))
        return object;
    if (types.isArray(object)) {
        return object.map(value => (value && types.isFunction(value.toJSON) ? value.toJSON() : toJSON(value)));
    }
    const original = props ? Object.values(props) : Object.keys(object);
    const keys = !props || types.isArray(props) ? original : Object.keys(props);
    return keys.reduce((plain, key, index) => {
        const value = object[original[index]];
        plain[key] = value && types.isFunction(value.toJSON) ? value.toJSON() : toJSON(value);
        return plain;
    }, {});
}
exports.toJSON = toJSON;
function toString(object) {
    return `${object.constructor.name} ${JSON.stringify(object, null, 2)}`;
}
exports.toString = toString;
function toUnAnchoredUri(url) {
    var _a;
    const [, result = url] = (_a = url.match(/(^[^#]*)/)) !== null && _a !== void 0 ? _a : [];
    return result === null || result === void 0 ? void 0 : result.replace(/\?\s*$/, '?');
}
exports.toUnAnchoredUri = toUnAnchoredUri;
function toUriEncoding(url) {
    return url.replace(/(\\[0-9a-fA-F]{1,6}\s?)/g, s => {
        return String.fromCodePoint(Number.parseInt(s.substring(1).trim(), 16));
    });
}
exports.toUriEncoding = toUriEncoding;
function removeUndefinedProps(object) {
    return Object.entries(object).reduce((object, [key, value]) => (value !== undefined ? Object.assign(object, { [key]: value }) : object), {});
}
exports.removeUndefinedProps = removeUndefinedProps;
function absolutizeUrl(url, baseUrl) {
    return new URL(url, baseUrl).href;
}
exports.absolutizeUrl = absolutizeUrl;
function cachify(func, getKey) {
    const cache = new Map();
    const funcWithCache = ((...args) => {
        var _a;
        const key = stringifyKey((_a = getKey === null || getKey === void 0 ? void 0 : getKey(args)) !== null && _a !== void 0 ? _a : args);
        let value = cache.get(key);
        if (!value) {
            value = func(...args);
            cache.set(key, value);
        }
        return value;
    });
    funcWithCache.clearCache = () => cache.clear();
    funcWithCache.getCachedValues = () => Array.from(cache.values());
    funcWithCache.setCachedValue = (key, value) => cache.set(stringifyKey(key), value);
    return funcWithCache;
    function stringifyKey(key) {
        key = types.isPlainObject(key)
            ? Object.fromEntries(Object.entries(key).sort(([key1], [key2]) => (key1 > key2 ? 1 : -1)))
            : key;
        return JSON.stringify(key, (_key, value) => (typeof value === 'function' ? value.toString() : value));
    }
}
exports.cachify = cachify;
function batchify(func, { timeout }) {
    let pendingInputs = new Map();
    let throttleTimer = false;
    return function (input) {
        return new Promise(async (resolve, reject) => {
            pendingInputs.set(input, { resolve, reject });
            if (!throttleTimer) {
                throttleTimer = true;
                setTimeout(() => {
                    func(Array.from(pendingInputs.entries()));
                    pendingInputs = new Map();
                    throttleTimer = false;
                }, timeout);
            }
        });
    };
}
exports.batchify = batchify;
function wrap(func, wrapper) {
    return new Proxy(func, {
        apply: (func, _this, args) => wrapper(func, ...args),
    });
}
exports.wrap = wrap;
function extend(target, extension) {
    const result = {};
    return Object.defineProperties(result, {
        ...Object.fromEntries(Object.entries(Object.getOwnPropertyDescriptors(target)).map(([key, descriptor]) => [
            key,
            types.isFunction(descriptor.value) || types.isObject(descriptor.value)
                ? descriptor
                : {
                    configurable: descriptor.configurable,
                    enumerable: descriptor.enumerable,
                    get: () => target[key],
                    set: value => (target[key] = value),
                },
        ])),
        ...Object.getOwnPropertyDescriptors(types.isFunction(extension) ? extension(result) : extension),
    });
}
exports.extend = extend;
function pluralize(object, config) {
    const count = types.isArray(object) ? object.length : object;
    const isMany = count > 1;
    let res = isMany ? 's' : '';
    if (config) {
        res = isMany ? config[0] : config[1];
    }
    return res;
}
exports.pluralize = pluralize;
