import { createClient } from 'redis';
import { CacheError } from './errors.js';
export async function createCache(config) {
    if (config.storage.cache === 'none') {
        return new NullCache();
    }
    if (config.storage.cache === 'memory') {
        return new MemoryCache();
    }
    const client = createClient({
        url: config.storage.redisUrl,
        socket: {
            reconnectStrategy: false,
        },
    });
    client.on('error', (error) => {
        console.error('[redis]', error.message);
    });
    try {
        await client.connect();
    }
    catch (error) {
        await client.disconnect().catch(() => undefined);
        throw new CacheError('Redis cache connection failed.', error);
    }
    return new RedisCache(client);
}
class RedisCache {
    client;
    constructor(client) {
        this.client = client;
    }
    async getJson(key) {
        try {
            const value = await this.client.get(key);
            return value ? JSON.parse(value) : undefined;
        }
        catch (error) {
            throw new CacheError('Redis cache read failed.', error);
        }
    }
    async setJson(key, value, ttlSeconds) {
        try {
            const encoded = JSON.stringify(value);
            if (ttlSeconds && ttlSeconds > 0) {
                await this.client.set(key, encoded, { EX: ttlSeconds });
                return;
            }
            await this.client.set(key, encoded);
        }
        catch (error) {
            throw new CacheError('Redis cache write failed.', error);
        }
    }
    async del(key) {
        try {
            await this.client.del(key);
        }
        catch (error) {
            throw new CacheError('Redis cache delete failed.', error);
        }
    }
    async close() {
        try {
            await this.client.quit();
        }
        catch (error) {
            throw new CacheError('Redis cache close failed.', error);
        }
    }
}
export class MemoryCache {
    values = new Map();
    async getJson(key) {
        const entry = this.values.get(key);
        if (!entry) {
            return undefined;
        }
        if (entry.expiresAt && entry.expiresAt < Date.now()) {
            this.values.delete(key);
            return undefined;
        }
        return entry.value;
    }
    async setJson(key, value, ttlSeconds) {
        this.values.set(key, {
            value,
            expiresAt: ttlSeconds ? Date.now() + ttlSeconds * 1000 : undefined,
        });
    }
    async del(key) {
        this.values.delete(key);
    }
    async close() { }
}
class NullCache {
    async getJson() {
        return undefined;
    }
    async setJson() { }
    async del() { }
    async close() { }
}
