"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTtlOverride = exports.cache = void 0;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const luxon_1 = require("luxon");
const global_1 = require("../../../config/global");
const logger_1 = require("../../../logger");
const decorator_1 = require("../../decorator");
const packageCache = tslib_1.__importStar(require("."));
/**
 * caches the result of a decorated method.
 */
function cache({ namespace, key, cacheable = () => true, ttlMinutes = 30, }) {
    return (0, decorator_1.decorate)(async ({ args, instance, callback, methodName }) => {
        const cachePrivatePackages = global_1.GlobalConfig.get('cachePrivatePackages', false);
        const isCacheable = cachePrivatePackages || cacheable.apply(instance, args);
        if (!isCacheable) {
            return callback();
        }
        let finalNamespace;
        if (is_1.default.string(namespace)) {
            finalNamespace = namespace;
        }
        else if (is_1.default.function_(namespace)) {
            finalNamespace = namespace.apply(instance, args);
        }
        let finalKey;
        if (is_1.default.string(key)) {
            finalKey = key;
        }
        else if (is_1.default.function_(key)) {
            finalKey = key.apply(instance, args);
        }
        // istanbul ignore if
        if (!finalNamespace || !finalKey) {
            return callback();
        }
        finalKey = `cache-decorator:${finalKey}`;
        const oldRecord = await packageCache.get(finalNamespace, finalKey);
        const ttlOverride = getTtlOverride(finalNamespace);
        const softTtl = ttlOverride ?? ttlMinutes;
        const cacheHardTtlMinutes = global_1.GlobalConfig.get('cacheHardTtlMinutes', 7 * 24 * 60);
        let hardTtl = softTtl;
        if (methodName === 'getReleases' || methodName === 'getDigest') {
            hardTtl = Math.max(softTtl, cacheHardTtlMinutes);
        }
        let oldData;
        if (oldRecord) {
            const now = luxon_1.DateTime.local();
            const cachedAt = luxon_1.DateTime.fromISO(oldRecord.cachedAt);
            const softDeadline = cachedAt.plus({ minutes: softTtl });
            if (now < softDeadline) {
                return oldRecord.value;
            }
            const hardDeadline = cachedAt.plus({ minutes: hardTtl });
            if (now < hardDeadline) {
                oldData = oldRecord.value;
            }
        }
        let newData;
        if (oldData) {
            try {
                newData = (await callback());
            }
            catch (err) {
                logger_1.logger.debug({ err }, 'Package cache decorator: callback error, returning old data');
                return oldData;
            }
        }
        else {
            newData = (await callback());
        }
        if (!is_1.default.undefined(newData)) {
            const newRecord = {
                cachedAt: luxon_1.DateTime.local().toISO(),
                value: newData,
            };
            await packageCache.set(finalNamespace, finalKey, newRecord, hardTtl);
        }
        return newData;
    });
}
exports.cache = cache;
function getTtlOverride(namespace) {
    const ttl = global_1.GlobalConfig.get('cacheTtlOverride', {})[namespace];
    if (is_1.default.number(ttl)) {
        return ttl;
    }
    return undefined;
}
exports.getTtlOverride = getTtlOverride;
//# sourceMappingURL=decorator.js.map