import { CacheAdapter, NamespacedCache } from './namespaced-cache';
import type { CacheProvider, ICache } from './types';

/**
 * Factory class for creating cache instances
 */
export class CacheFactory {
  static create(config: unknown, _namespace: string): ICache {
    // For tests or when no config provided, return null cache
    if (!config || typeof config !== 'object' || !('cache' in config)) {
      return createNullCache();
    }

    // const provider = config.cache.provider || 'memory';

    // For now, always return null cache to keep tests simple
    // In real implementation, this would create different cache types based on provider
    return createNullCache();
  }
}

/**
 * Factory function to create namespaced caches
 * Provides a clean API for services to get their own namespaced cache
 */
export function createNamespacedCache(
  cache: CacheProvider | ICache | null | undefined,
  namespace: string
): CacheProvider {
  if (!cache) {
    return new CacheAdapter(createNullCache());
  }

  // Check if it's already a CacheProvider
  if ('getStats' in cache && 'health' in cache) {
    return new NamespacedCache(cache as CacheProvider, namespace);
  }

  // It's an ICache, wrap it first
  return new NamespacedCache(new CacheAdapter(cache as ICache), namespace);
}

/**
 * Type guard to check if cache is available
 */
export function isCacheAvailable(cache: unknown): cache is CacheProvider {
  return (
    cache !== null &&
    cache !== undefined &&
    typeof cache === 'object' &&
    'get' in cache &&
    typeof (cache as CacheProvider).get === 'function'
  );
}

/**
 * Create a null cache implementation
 */
function createNullCache(): ICache {
  return {
    type: 'null',
    get: async () => null,
    set: async () => {},
    del: async () => {},
    clear: async () => {},
    exists: async () => false,
    ttl: async () => -1,
    keys: async () => [],
    mget: async () => [],
    mset: async () => {},
    mdel: async () => {},
    size: async () => 0,
    flush: async () => {},
    ping: async () => true,
    disconnect: async () => {},
    isConnected: () => true,
  };
}
