import { regEx } from "../../regex.js";
import { logger } from "../../../logger/index.js";
import { compressToBase64, decompressFromBase64 } from "../../compress.js";
import { DateTime } from "luxon";
import { createClient, createCluster } from "redis";

//#region lib/util/cache/package/redis.ts
let client;
let rprefix;
function getKey(namespace, key) {
	return `${rprefix}${namespace}-${key}`;
}
function normalizeRedisUrl(url) {
	return url.replace(regEx(/^(rediss?)\+cluster:\/\//), "$1://");
}
async function end() {
	try {
		await client?.disconnect();
	} catch (err) {
		logger.warn({ err }, "Redis cache end failed");
	}
}
async function rm(namespace, key) {
	logger.trace({
		rprefix,
		namespace,
		key
	}, "Removing cache entry");
	await client?.del(getKey(namespace, key));
}
async function get(namespace, key) {
	if (!client) return;
	logger.trace(`cache.get(${namespace}, ${key})`);
	try {
		const res = await client?.get(getKey(namespace, key));
		const cachedValue = res && JSON.parse(res);
		if (cachedValue) {
			if (DateTime.local() < DateTime.fromISO(cachedValue.expiry)) {
				logger.trace({
					rprefix,
					namespace,
					key
				}, "Returning cached value");
				// istanbul ignore if
				if (!cachedValue.compress) return cachedValue.value;
				const res = await decompressFromBase64(cachedValue.value);
				return JSON.parse(res);
			}
			// istanbul ignore next
			await rm(namespace, key);
		}
	} catch {
		logger.trace({
			rprefix,
			namespace,
			key
		}, "Cache miss");
	}
}
async function set(namespace, key, value, hardTtlMinutes = 5) {
	logger.trace({
		rprefix,
		namespace,
		key,
		hardTtlMinutes
	}, "Saving cached value");
	const redisTTL = Math.floor(hardTtlMinutes * 60);
	try {
		await client?.set(getKey(namespace, key), JSON.stringify({
			compress: true,
			value: await compressToBase64(JSON.stringify(value)),
			expiry: DateTime.local().plus({ minutes: hardTtlMinutes })
		}), { EX: redisTTL });
	} catch (err) {
		logger.once.warn({ err }, "Error while setting Redis cache value");
	}
}
async function init(url, prefix) {
	if (!url) return;
	rprefix = prefix ?? "";
	logger.debug("Redis cache init");
	const rewrittenUrl = normalizeRedisUrl(url);
	const clusteredMode = rewrittenUrl.length !== url.length;
	const config = {
		url: rewrittenUrl,
		socket: { reconnectStrategy: (retries) => {
			return Math.min(retries * 100, 3e3);
		} },
		pingInterval: 3e4
	};
	if (clusteredMode) {
		const clusterConfig = { rootNodes: [config] };
		const parsedUrl = new URL(rewrittenUrl);
		if (parsedUrl.username) clusterConfig.defaults = { username: parsedUrl.username };
		if (parsedUrl.password) {
			clusterConfig.defaults ??= {};
			clusterConfig.defaults.password = parsedUrl.password;
		}
		client = createCluster(clusterConfig);
	} else client = createClient(config);
	await client.connect();
	logger.debug("Redis cache connected");
}

//#endregion
export { end, get, init, normalizeRedisUrl, set };
//# sourceMappingURL=redis.js.map