/**
 * Cache Service - Main entry point with DI
 * Simple constructor-based dependency injection
 */

import type { CacheAdapter, CacheConfig } from './interfaces';
import { MemoryCacheAdapter } from './memory-adapter';
import { RedisCacheAdapter } from './redis-adapter';

export class CacheService {
  private adapter: CacheAdapter;

  /**
   * Create cache service with dependency injection
   * @param adapter - Cache adapter implementation
   */
  constructor(adapter: CacheAdapter) {
    this.adapter = adapter;
  }

  async get<T>(key: string): Promise<T | null> {
    return this.adapter.get<T>(key);
  }

  async set<T>(key: string, value: T, ttl?: number): Promise<void> {
    return this.adapter.set(key, value, ttl);
  }

  async del(key: string): Promise<void> {
    return this.adapter.del(key);
  }

  async clear(): Promise<void> {
    return this.adapter.clear();
  }

  /**
   * Cache wrapper for functions
   * Returns cached result or executes function and caches result
   */
  async wrap<T>(key: string, fn: () => Promise<T>, ttl?: number): Promise<T> {
    const cached = await this.get<T>(key);
    if (cached !== null) return cached;

    const result = await fn();
    await this.set(key, result, ttl);
    return result;
  }
}

// Factory functions for easy instantiation
export function createMemoryCache(config?: CacheConfig): CacheService {
  return new CacheService(new MemoryCacheAdapter(config));
}

export function createRedisCache(config?: CacheConfig & { redisUrl?: string }): CacheService {
  return new CacheService(new RedisCacheAdapter(config));
}

// Default singleton instance - uses Redis if available, otherwise Memory
let defaultCache: CacheService | null = null;

export async function getDefaultCache(): Promise<CacheService> {
  if (!defaultCache) {
    // Try Redis first
    const redisAdapter = new RedisCacheAdapter({
      prefix: 'mintel:blog:',
      defaultTTL: 3600
    });
    
    const redisAvailable = await redisAdapter.get('__test__')
      .then(() => true)
      .catch(() => false);
    
    if (redisAvailable) {
      console.log('✅ Using Redis cache');
      defaultCache = new CacheService(redisAdapter);
    } else {
      console.log('⚠️  Redis unavailable, using Memory cache');
      defaultCache = createMemoryCache({
        prefix: 'mintel:blog:',
        defaultTTL: 3600
      });
    }
  }
  return defaultCache;
}

// Convenience function using default cache
export async function withCache<T>(
  key: string,
  fn: () => Promise<T>,
  ttl?: number
): Promise<T> {
  const cache = await getDefaultCache();
  return cache.wrap(key, fn, ttl);
}

// Re-export interfaces and adapters for advanced usage
export type { CacheAdapter, CacheConfig };
export { MemoryCacheAdapter, RedisCacheAdapter };