"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 __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.highestRateLimitTiers = exports.buildRateLimitTiersFromConfig = exports.getRateLimitingTier = exports.lowestTierLimit = exports.highestTierLimit = exports.consolidateTierLimits = void 0;
const util_1 = require("../util");
__exportStar(require("./burst"), exports);
const logger = (0, util_1.makeLogger)('RateLimitingUtils');
/**
 * This method will convert all possible settings for a rate limit tier and
 * convert them all to requests per second
 *
 * @param limits - the rate limit tier set for the adapter
 * @returns all rate limits values in seconds
 */
const consolidateTierLimits = (limits) => {
    const perHourLimit = (limits?.rateLimit1h || Infinity) / (60 * 60);
    const perMinuteLimit = (limits?.rateLimit1m || Infinity) / 60;
    const perSecondLimit = limits?.rateLimit1s || Infinity;
    return [perHourLimit, perMinuteLimit, perSecondLimit];
};
exports.consolidateTierLimits = consolidateTierLimits;
/**
 * This method will convert all possible settings for a rate limit tier and
 * convert them all to requests per second, returning the highest one
 *
 * @param limits - the rate limit tier set for the adapter
 * @returns the most permissive of the set options, in requests per second
 */
const highestTierLimit = (limits) => {
    const consolidateLimits = (0, exports.consolidateTierLimits)(limits).map((tier) => {
        if (tier === Infinity) {
            return 0;
        }
        return tier;
    });
    return Math.max(...consolidateLimits);
};
exports.highestTierLimit = highestTierLimit;
/**
 * This method will convert all possible settings for a rate limit tier and
 * convert them all to requests per second, returning the lowest one
 *
 * @param limits - the rate limit tier set for the adapter
 * @returns the most restrictive of the set options, in requests per second
 */
const lowestTierLimit = (limits) => {
    return Math.min(...(0, exports.consolidateTierLimits)(limits));
};
exports.lowestTierLimit = lowestTierLimit;
/**
 * Validates rate limiting tiers specified for the adapter, and returns the one to use.
 *
 * @param adapterSettings - the adapter config containing the env vars
 * @param tiers - the adapter config listing the different available API tiers
 * @returns the specified API tier, or a default one if none are specified
 */
const getRateLimitingTier = (adapterSettings, tiers) => {
    if (adapterSettings.RATE_LIMIT_CAPACITY ||
        adapterSettings.RATE_LIMIT_CAPACITY_MINUTE ||
        adapterSettings.RATE_LIMIT_CAPACITY_SECOND) {
        return (0, exports.buildRateLimitTiersFromConfig)(adapterSettings);
    }
    if (!tiers) {
        return;
    }
    // Check that if the tiers object is defined, it has values
    if (Object.values(tiers).length === 0) {
        throw new Error(`The tiers object is defined, but has no entries`);
    }
    // Check that the tier set in the AdapterConfig is a valid one
    const selectedTier = adapterSettings.RATE_LIMIT_API_TIER;
    if (selectedTier && !tiers[selectedTier]) {
        const validTiersString = Object.keys(tiers)
            .map((t) => `"${t}"`)
            .join(', ');
        throw new Error(`The selected rate limit tier "${selectedTier}" is not valid (can be one of ${validTiersString})`);
    }
    if (!selectedTier) {
        // Sort the tiers by most to least restrictive
        const sortedTiers = Object.entries(tiers).sort(([_, t1], [__, t2]) => (0, exports.lowestTierLimit)(t1) - (0, exports.lowestTierLimit)(t2));
        const [selectedName, selectedLimits] = sortedTiers[0];
        logger.info(`There was no rate limiting tier specified, will use lowest one (${selectedName})`);
        return selectedLimits;
    }
    logger.info(`Using specified tier "${selectedTier}"`);
    return tiers[selectedTier];
};
exports.getRateLimitingTier = getRateLimitingTier;
// Creates adapter rate limit tier using the configs specified in env vars
const buildRateLimitTiersFromConfig = (adapterSettings) => {
    const rateLimit1s = adapterSettings.RATE_LIMIT_CAPACITY_SECOND;
    let rateLimit1m;
    if (adapterSettings.RATE_LIMIT_CAPACITY_MINUTE) {
        rateLimit1m = adapterSettings.RATE_LIMIT_CAPACITY_MINUTE;
    }
    else if (adapterSettings.RATE_LIMIT_CAPACITY) {
        rateLimit1m = adapterSettings.RATE_LIMIT_CAPACITY;
    }
    return {
        rateLimit1s,
        rateLimit1m,
    };
};
exports.buildRateLimitTiersFromConfig = buildRateLimitTiersFromConfig;
const highestRateLimitTiers = (tiers) => {
    if (!tiers) {
        return 0;
    }
    if (Object.values(tiers).length === 0) {
        throw new Error(`The tiers object is defined, but has no entries`);
    }
    // Sort tiers in a descending way
    const highestTiers = Object.values(tiers).sort((t1, t2) => (0, exports.highestTierLimit)(t2) - (0, exports.highestTierLimit)(t1));
    return (0, exports.highestTierLimit)(highestTiers[0]);
};
exports.highestRateLimitTiers = highestRateLimitTiers;
//# sourceMappingURL=index.js.map