import { getGlobalRedisClient } from "./redis-client.js";
import { getRedisUrl, isRedis } from "./redis-client-helpers.js";
import { isTrueString } from "../../is.js";
const DEFAULT_TIMEOUT = 2500;
const DEFAULT_RETRY_DELAY = 25;
const GLOBAL_LOCKS = new Map();
export function isLocking() {
    return !!getGlobalLock();
}
export function isConfigurableNameLocking(name) {
    const key = `LOCK_${name.toUpperCase().replace(/[^a-z]+/g, "_")}`;
    return isTrueString(process.env[key]);
}
export async function configurableLock(name) {
    if (!isConfigurableNameLocking(name)) {
        return createFakeLock();
    }
    return lock(name);
}
export async function lock(name) {
    const fn = getGlobalLock();
    if (!fn) {
        // noop for now
        return createFakeLock();
    }
    return fn(name);
}
export function createFakeLock() {
    return async () => {
        return void 0; // noop
    };
}
export function getGlobalLock() {
    if (!isRedis())
        return undefined;
    const url = getRedisUrl();
    const existing = GLOBAL_LOCKS.get(url);
    if (existing)
        return existing;
    const fn = async (name) => {
        const client = await getGlobalRedisClient();
        return acquire(client, name);
    };
    GLOBAL_LOCKS.set(url, fn);
    return;
}
async function acquire(client, name) {
    const timeout = DEFAULT_TIMEOUT;
    const timeoutAfter = Date.now() + timeout + 1;
    const key = `lock::${name}`;
    return await tryAcquire();
    async function unlock() {
        await client.del(key);
    }
    async function tryAcquire() {
        try {
            const result = await client.set(key, timeoutAfter, "PX", timeout, "NX");
            if (result) {
                return unlock;
            }
        }
        catch { }
        await new Promise(resolve => setTimeout(resolve, DEFAULT_RETRY_DELAY));
        return tryAcquire();
    }
}
//# sourceMappingURL=lock.js.map