"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isCacheEnabled = exports.clearCache = exports.disableCache = exports.enableCache = exports.fetchWithCache = exports.getCache = void 0;
const cache_manager_1 = __importDefault(require("cache-manager"));
const cache_manager_fs_hash_1 = __importDefault(require("cache-manager-fs-hash"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const fetch_1 = require("./fetch");
const logger_1 = __importDefault(require("./logger"));
const util_1 = require("./util");
let cacheInstance;
let enabled = typeof process.env.PROMPTFOO_CACHE_ENABLED === 'undefined'
    ? true
    : process.env.PROMPTFOO_CACHE_ENABLED === '1' ||
        process.env.PROMPTFOO_CACHE_ENABLED === 'true' ||
        process.env.PROMPTFOO_CACHE_ENABLED === 'yes';
const cacheType = process.env.PROMPTFOO_CACHE_TYPE || (process.env.NODE_ENV === 'test' ? 'memory' : 'disk');
function getCache() {
    if (!cacheInstance) {
        let cachePath = '';
        if (cacheType === 'disk' && enabled) {
            cachePath = process.env.PROMPTFOO_CACHE_PATH || path_1.default.join((0, util_1.getConfigDirectoryPath)(), 'cache');
            if (!fs_1.default.existsSync(cachePath)) {
                logger_1.default.info(`Creating cache folder at ${cachePath}.`);
                fs_1.default.mkdirSync(cachePath, { recursive: true });
            }
        }
        cacheInstance = cache_manager_1.default.caching({
            store: cacheType === 'disk' && enabled ? cache_manager_fs_hash_1.default : 'memory',
            options: {
                max: process.env.PROMPTFOO_CACHE_MAX_FILE_COUNT || 10000, // number of files
                path: cachePath,
                ttl: process.env.PROMPTFOO_CACHE_TTL || 60 * 60 * 24 * 14, // in seconds, 14 days
                maxsize: process.env.PROMPTFOO_CACHE_MAX_SIZE || 1e7, // in bytes, 10mb
                //zip: true, // whether to use gzip compression
            },
        });
    }
    return cacheInstance;
}
exports.getCache = getCache;
async function fetchWithCache(url, options = {}, timeout, format = 'json', bust = false) {
    if (!enabled || bust) {
        const resp = await (0, fetch_1.fetchWithRetries)(url, options, timeout);
        const respText = await resp.text();
        try {
            return {
                cached: false,
                data: format === 'json' ? JSON.parse(respText) : respText,
            };
        }
        catch (error) {
            throw new Error(`Error parsing response as JSON: ${respText}`);
        }
    }
    const cache = await getCache();
    const copy = Object.assign({}, options);
    delete copy.headers;
    const cacheKey = `fetch:${url}:${JSON.stringify(copy)}`;
    let cached = true;
    let errorResponse = null;
    // Use wrap to ensure that the fetch is only done once even for concurrent invocations
    const cachedResponse = await cache.wrap(cacheKey, async () => {
        // Fetch the actual data and store it in the cache
        cached = false;
        const response = await (0, fetch_1.fetchWithRetries)(url, options, timeout);
        const responseText = await response.text();
        try {
            const data = JSON.stringify(format === 'json' ? JSON.parse(responseText) : responseText);
            if (!response.ok) {
                errorResponse = data;
                // Don't cache error responses
                return;
            }
            if (!data) {
                // Don't cache empty responses
                return;
            }
            logger_1.default.debug(`Storing ${url} response in cache: ${data}`);
            return data;
        }
        catch (err) {
            throw new Error(`Error parsing response from ${url}: ${err.message}. Received text: ${responseText}`);
        }
    });
    if (cached && cachedResponse) {
        logger_1.default.debug(`Returning cached response for ${url}: ${cachedResponse}`);
    }
    return {
        cached,
        data: JSON.parse((cachedResponse ?? errorResponse)),
    };
}
exports.fetchWithCache = fetchWithCache;
function enableCache() {
    enabled = true;
}
exports.enableCache = enableCache;
function disableCache() {
    enabled = false;
}
exports.disableCache = disableCache;
async function clearCache() {
    return getCache().reset();
}
exports.clearCache = clearCache;
function isCacheEnabled() {
    return enabled;
}
exports.isCacheEnabled = isCacheEnabled;
//# sourceMappingURL=cache.js.map