/**
 * Cache Configuration
 * Caching drivers and settings
 * Sealed namespace for immutability
 */
import { Cloudflare } from './cloudflare.js';
import { Env } from './env.js';
import { ErrorFactory } from '../exceptions/ZintrustError.js';
import { StartupConfigFile, StartupConfigFileRegistry } from '../runtime/StartupConfigFileRegistry.js';
const getCacheDriver = (config, name) => {
    const selected = String(name ?? config.default).trim();
    const storeName = selected === 'default' ? String(config.default).trim() : selected;
    const isExplicitSelection = name !== undefined && String(name).trim().length > 0 && String(name).trim() !== 'default';
    if (storeName.length > 0 && Object.hasOwn(config.drivers, storeName)) {
        const resolved = config.drivers[storeName];
        if (resolved !== undefined)
            return resolved;
    }
    if (isExplicitSelection) {
        throw ErrorFactory.createConfigError(`Cache store not configured: ${storeName}`);
    }
    if (Object.keys(config.drivers ?? {}).length === 0) {
        throw ErrorFactory.createConfigError('No cache stores are configured');
    }
    throw ErrorFactory.createConfigError(`Cache default store not configured: ${storeName || '<empty>'}`);
};
const readWorkersEnvString = (key) => {
    const workerValue = Cloudflare.getWorkersVar(key);
    if (workerValue !== null && workerValue.trim() !== '')
        return workerValue;
    return '';
};
const readWorkersFallbackString = (workersKey, fallbackKey, fallback = '') => {
    const workerValue = readWorkersEnvString(workersKey);
    if (workerValue.trim() !== '')
        return workerValue;
    return Env.get(fallbackKey, fallback);
};
const readWorkersFallbackInt = (workersKey, fallbackKey, fallback) => {
    const raw = readWorkersFallbackString(workersKey, fallbackKey, String(fallback));
    if (raw.trim() === '')
        return fallback;
    const parsed = Number.parseInt(raw, 10);
    return Number.isFinite(parsed) ? parsed : fallback;
};
const createCacheConfig = () => {
    const baseDefault = (() => {
        const envConnection = Env.get('CACHE_CONNECTION', '').trim();
        const envDriver = typeof Env.CACHE_DRIVER === 'string'
            ? String(Env.CACHE_DRIVER)
            : Env.get('CACHE_DRIVER', 'memory');
        const selected = envConnection.length > 0 ? envConnection : String(envDriver ?? 'memory');
        return selected.trim().toLowerCase();
    })();
    const baseDrivers = {
        memory: {
            driver: 'memory',
            ttl: Env.getInt('CACHE_MEMORY_TTL', 3600),
        },
        redis: {
            driver: 'redis',
            host: readWorkersFallbackString('WORKERS_REDIS_HOST', 'REDIS_HOST', 'localhost'),
            port: readWorkersFallbackInt('WORKERS_REDIS_PORT', 'REDIS_PORT', 6379),
            ttl: Env.getInt('CACHE_REDIS_TTL', 3600),
        },
        mongodb: {
            driver: 'mongodb',
            uri: Env.get('MONGO_URI'),
            db: Env.get('MONGO_DB', 'zintrust_cache'),
            ttl: Env.getInt('CACHE_MONGO_TTL', 3600),
        },
        kv: {
            driver: 'kv',
            ttl: Env.getInt('CACHE_KV_TTL', 3600),
        },
        'kv-remote': {
            driver: 'kv-remote',
            ttl: Env.getInt('CACHE_KV_TTL', 3600),
        },
    };
    const overrides = StartupConfigFileRegistry.get(StartupConfigFile.Cache) ?? {};
    const mergedDrivers = {
        ...baseDrivers,
        ...overrides.drivers,
    };
    const mergedDefault = typeof overrides.default === 'string' && overrides.default.trim() !== ''
        ? overrides.default.trim().toLowerCase()
        : baseDefault;
    const mergedKeyPrefix = typeof overrides.keyPrefix === 'string' && overrides.keyPrefix.length > 0
        ? overrides.keyPrefix
        : Env.get('CACHE_KEY_PREFIX', 'zintrust:');
    const mergedTtl = typeof overrides.ttl === 'number' && Number.isFinite(overrides.ttl) ? overrides.ttl : 3600;
    const cacheConfigObj = {
        /**
         * Default cache driver
         */
        default: mergedDefault,
        /**
         * Cache drivers
         */
        drivers: mergedDrivers,
        /**
         * Get cache driver config
         */
        getDriver(name) {
            return getCacheDriver(this, name);
        },
        /**
         * Key prefix for all cache keys
         */
        keyPrefix: mergedKeyPrefix,
        /**
         * Default cache TTL (seconds)
         */
        ttl: mergedTtl,
    };
    return Object.freeze(cacheConfigObj);
};
let cached = null;
const proxyTarget = {};
const ensureCacheConfig = () => {
    if (cached)
        return cached;
    cached = createCacheConfig();
    try {
        Object.defineProperties(proxyTarget, Object.getOwnPropertyDescriptors(cached));
    }
    catch {
        // best-effort
    }
    return cached;
};
export const cacheConfig = new Proxy(proxyTarget, {
    get(_target, prop) {
        return ensureCacheConfig()[prop];
    },
    ownKeys() {
        ensureCacheConfig();
        return Reflect.ownKeys(proxyTarget);
    },
    getOwnPropertyDescriptor(_target, prop) {
        ensureCacheConfig();
        return Object.getOwnPropertyDescriptor(proxyTarget, prop);
    },
});
