/* eslint-disable @typescript-eslint/require-await */
/**
 * Cache Manager
 * Central cache management and driver resolution
 * Sealed namespace pattern - all exports through Cache namespace
 */
import { CacheDriverRegistry } from './CacheDriverRegistry.js';
import { KVDriver } from './drivers/KVDriver.js';
import { KVRemoteDriver } from './drivers/KVRemoteDriver.js';
import { MemoryDriver } from './drivers/MemoryDriver.js';
import { MongoDriver } from './drivers/MongoDriver.js';
import { RedisDriver } from './drivers/RedisDriver.js';
import { cacheConfig } from '../config/cache.js';
import { Env } from '../config/env.js';
import { ErrorFactory } from '../exceptions/ZintrustError.js';
const instances = new Map();
/**
 * Auto-prefix cache keys with 'zt:' if not already prefixed
 */
function autoPrefixKey(key) {
    return key.startsWith('zt:') ? key : `zt:${key}`;
}
function createNoOpDriver() {
    return {
        get: async () => null,
        set: async () => { },
        delete: async () => { },
        clear: async () => { },
        has: async () => false,
    };
}
function buildDriver(driver) {
    const maybeCreate = driver.create;
    if (typeof maybeCreate === 'function') {
        return maybeCreate();
    }
    if (typeof driver === 'function') {
        return new driver();
    }
    throw ErrorFactory.createGeneralError('Invalid cache driver export');
}
function resolveDriver(storeName) {
    const cacheEnabledRaw = Env.get('CACHE_ENABLED', 'true').trim().toLowerCase();
    const cacheEnabled = !(cacheEnabledRaw === 'false' ||
        cacheEnabledRaw === '0' ||
        cacheEnabledRaw === 'no');
    if (!cacheEnabled) {
        return createNoOpDriver();
    }
    const driverConfig = cacheConfig.getDriver(storeName);
    const externalFactory = CacheDriverRegistry.get(driverConfig.driver);
    if (externalFactory !== undefined) {
        return externalFactory(driverConfig);
    }
    const driverName = driverConfig.driver;
    switch (driverName) {
        case 'kv':
            return buildDriver(KVDriver);
        case 'kv-remote':
            return buildDriver(KVRemoteDriver);
        case 'redis':
            return buildDriver(RedisDriver);
        case 'mongodb':
            return buildDriver(MongoDriver);
        case 'memory':
        default:
            return buildDriver(MemoryDriver);
    }
}
function getDriverInstance(storeName) {
    const normalizedSelection = String(storeName ?? '')
        .trim()
        .toLowerCase();
    const resolvedKey = normalizedSelection.length > 0 ? normalizedSelection : 'default';
    const existing = instances.get(resolvedKey);
    if (existing !== undefined)
        return existing;
    const selector = resolvedKey === 'default' ? undefined : resolvedKey;
    const created = resolveDriver(selector);
    instances.set(resolvedKey, created);
    return created;
}
/**
 * Get an item from the cache
 */
const get = async (key) => {
    const prefixedKey = autoPrefixKey(key);
    const value = await getDriverInstance().get(prefixedKey);
    return value;
};
/**
 * Store an item in the cache
 */
const set = async (key, value, ttl) => {
    const prefixedKey = autoPrefixKey(key);
    await getDriverInstance().set(prefixedKey, value, ttl);
};
/**
 * Remove an item from the cache
 */
const del = async (key) => {
    const prefixedKey = autoPrefixKey(key);
    await getDriverInstance().delete(prefixedKey);
};
/**
 * Clear all items from the cache
 */
const clear = async () => {
    await getDriverInstance().clear();
};
/**
 * Check if an item exists in the cache
 */
const has = async (key) => {
    const prefixedKey = autoPrefixKey(key);
    const exists = await getDriverInstance().has(prefixedKey);
    return exists;
};
/**
 * Get the underlying driver instance
 */
const getDriver = () => {
    return getDriverInstance();
};
const store = (name) => {
    const getFromStore = async (key) => {
        const prefixedKey = autoPrefixKey(key);
        return getDriverInstance(name).get(prefixedKey);
    };
    const setInStore = async (key, value, ttl) => {
        const prefixedKey = autoPrefixKey(key);
        await getDriverInstance(name).set(prefixedKey, value, ttl);
    };
    const delFromStore = async (key) => {
        const prefixedKey = autoPrefixKey(key);
        await getDriverInstance(name).delete(prefixedKey);
    };
    const clearStore = async () => {
        await getDriverInstance(name).clear();
    };
    const hasInStore = async (key) => {
        const prefixedKey = autoPrefixKey(key);
        return getDriverInstance(name).has(prefixedKey);
    };
    const getStoreDriver = () => {
        return getDriverInstance(name);
    };
    return Object.freeze({
        get: getFromStore,
        set: setInStore,
        delete: delFromStore,
        clear: clearStore,
        has: hasInStore,
        getDriver: getStoreDriver,
    });
};
const reset = () => {
    instances.clear();
};
// Sealed namespace with cache functionality
export const Cache = Object.freeze({
    get,
    set,
    delete: del,
    clear,
    has,
    getDriver,
    store,
    reset,
});
/**
 * Helper alias for cache
 */
export const cache = Cache;
