import { Cloudflare, Env, ErrorFactory, Logger, createRedisConnection } from '../../../src/index.js';
import { RedisProxyAdapter } from './RedisProxyAdapter.js';
const safeJsonParse = (value) => {
    try {
        return JSON.parse(value);
    }
    catch {
        return null;
    }
};
async function importRedis() {
    return (await import('redis'));
}
const createCacheOperations = (ensureClient, operations, defaultTtl) => {
    return {
        async get(key) {
            try {
                const client = await ensureClient();
                const value = await operations.get(client, key);
                if (value === null)
                    return null;
                return safeJsonParse(value);
            }
            catch (error) {
                Logger.error('Redis cache GET failed', error);
                return null;
            }
        },
        async set(key, value, ttl) {
            const client = await ensureClient();
            const json = JSON.stringify(value);
            const effectiveTtl = ttl ?? defaultTtl;
            await operations.set(client, key, json, effectiveTtl);
        },
        async delete(key) {
            const client = await ensureClient();
            await operations.del(client, key);
        },
        async clear() {
            const client = await ensureClient();
            await operations.clear(client);
        },
        async has(key) {
            const client = await ensureClient();
            const count = await operations.exists(client, key);
            return count > 0;
        },
    };
};
const createWorkersCacheDriver = (config) => {
    let client;
    let connected = false;
    const ensureClient = async () => {
        if (client === undefined) {
            client = createRedisConnection({
                host: config.host,
                port: config.port,
                password: config.password,
                db: config.database ?? 0,
            });
        }
        if (!connected && typeof client.connect === 'function') {
            await client.connect();
            connected = true;
        }
        return client;
    };
    return createCacheOperations(ensureClient, {
        get: (redisClient, key) => redisClient.get(key),
        set: (redisClient, key, json, ttl) => {
            if (Number.isFinite(ttl) && ttl > 0) {
                return redisClient.set(key, json, { EX: ttl });
            }
            else {
                return redisClient.set(key, json);
            }
        },
        del: (redisClient, key) => {
            redisClient.del(key);
            return Promise.resolve();
        },
        clear: (redisClient) => {
            if (typeof redisClient.flushDb === 'function') {
                return redisClient.flushDb();
            }
            else if (typeof redisClient.flushdb === 'function') {
                return redisClient.flushdb();
            }
            return Promise.resolve();
        },
        exists: (redisClient, key) => redisClient.exists(key),
    }, config.ttl ?? 300);
};
const createNodeCacheDriver = (config) => {
    let client;
    let connected = false;
    const ensureClient = async () => {
        if (client === undefined) {
            const { createClient } = await importRedis();
            client = createClient({ socket: { host: config.host, port: config.port } });
        }
        if (!connected) {
            await client.connect();
            connected = true;
        }
        return client;
    };
    return createCacheOperations(ensureClient, {
        get: (redisClient, key) => redisClient.get(key),
        set: (redisClient, key, json, ttl) => {
            if (Number.isFinite(ttl) && ttl > 0) {
                return redisClient.set(key, json, { EX: ttl });
            }
            else {
                return redisClient.set(key, json);
            }
        },
        del: (redisClient, key) => {
            redisClient.del(key);
            return Promise.resolve();
        },
        clear: (redisClient) => {
            redisClient.flushDb();
            return Promise.resolve();
        },
        exists: (redisClient, key) => redisClient.exists(key),
    }, config.ttl ?? 300);
};
const shouldUseProxy = () => {
    if (Env.REDIS_PROXY_URL.trim() !== '')
        return true;
    return Env.USE_REDIS_PROXY === true;
};
export const RedisCacheDriver = Object.freeze({
    create(config) {
        const isWorkers = Cloudflare.getWorkersEnv() !== null;
        if (shouldUseProxy()) {
            return RedisProxyAdapter.create();
        }
        if (isWorkers && Cloudflare.isCloudflareSocketsEnabled() === false) {
            throw ErrorFactory.createConfigError('Redis cache driver requires ENABLE_CLOUDFLARE_SOCKETS=true in Cloudflare Workers.');
        }
        return isWorkers ? createWorkersCacheDriver(config) : createNodeCacheDriver(config);
    },
});
export default RedisCacheDriver;
export { RedisProxyAdapter } from './RedisProxyAdapter.js';
/**
 * Package version and build metadata
 * Available at runtime for debugging and health checks
 */
export const _ZINTRUST_CACHE_REDIS_VERSION = '0.1.15';
export const _ZINTRUST_CACHE_REDIS_BUILD_DATE = '__BUILD_DATE__';
