/**
 * API 응답 캐싱 서비스
 * - 메모리 기반 캐시로 동일한 요청 중복 방지
 * - TTL(Time To Live) 기반 자동 만료
 * - LRU(Least Recently Used) 캐시 정책
 */

interface CacheEntry<T> {
  data: T;
  timestamp: number;
  ttl: number; // milliseconds
}

interface CacheOptions {
  ttl?: number; // 기본 5분
  maxSize?: number; // 최대 캐시 항목 수
}

class ApiCacheService {
  private cache = new Map<string, CacheEntry<any>>();
  private accessOrder: string[] = []; // LRU 추적용
  private defaultTTL = 5 * 60 * 1000; // 5분
  private maxSize = 100;

  /**
   * 캐시에서 데이터 가져오기
   */
  get<T>(key: string): T | null {
    const entry = this.cache.get(key);
    
    if (!entry) {
      return null;
    }

    // TTL 확인
    const now = Date.now();
    if (now - entry.timestamp > entry.ttl) {
      this.cache.delete(key);
      this.removeFromAccessOrder(key);
      return null;
    }

    // LRU 업데이트
    this.updateAccessOrder(key);
    
    return entry.data as T;
  }

  /**
   * 캐시에 데이터 저장
   */
  set<T>(key: string, data: T, options?: CacheOptions): void {
    const ttl = options?.ttl || this.defaultTTL;
    
    // 최대 크기 초과 시 가장 오래된 항목 제거
    if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
      const oldestKey = this.accessOrder[0];
      if (oldestKey) {
        this.cache.delete(oldestKey);
        this.removeFromAccessOrder(oldestKey);
      }
    }

    this.cache.set(key, {
      data,
      timestamp: Date.now(),
      ttl,
    });

    this.updateAccessOrder(key);
  }

  /**
   * 특정 키 패턴과 일치하는 캐시 무효화
   */
  invalidate(pattern: string | RegExp): void {
    const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
    
    for (const key of Array.from(this.cache.keys())) {
      if (regex.test(key)) {
        this.cache.delete(key);
        this.removeFromAccessOrder(key);
      }
    }
  }

  /**
   * 특정 키의 캐시 삭제
   */
  delete(key: string): void {
    this.cache.delete(key);
    this.removeFromAccessOrder(key);
  }

  /**
   * 모든 캐시 삭제
   */
  clear(): void {
    this.cache.clear();
    this.accessOrder = [];
  }

  /**
   * 만료된 캐시 항목 정리
   */
  cleanup(): void {
    const now = Date.now();
    
    for (const [key, entry] of Array.from(this.cache.entries())) {
      if (now - entry.timestamp > entry.ttl) {
        this.cache.delete(key);
        this.removeFromAccessOrder(key);
      }
    }
  }

  /**
   * 캐시 키 생성 헬퍼
   */
  createKey(prefix: string, params: Record<string, any>): string {
    const sortedParams = Object.keys(params)
      .sort()
      .map(k => `${k}=${JSON.stringify(params[k])}`)
      .join('&');
    
    return `${prefix}:${sortedParams}`;
  }

  /**
   * LRU 접근 순서 업데이트
   */
  private updateAccessOrder(key: string): void {
    this.removeFromAccessOrder(key);
    this.accessOrder.push(key);
  }

  /**
   * LRU 접근 순서에서 제거
   */
  private removeFromAccessOrder(key: string): void {
    const index = this.accessOrder.indexOf(key);
    if (index > -1) {
      this.accessOrder.splice(index, 1);
    }
  }

  /**
   * 캐시 통계
   */
  getStats() {
    return {
      size: this.cache.size,
      maxSize: this.maxSize,
      keys: Array.from(this.cache.keys()),
    };
  }
}

// 싱글톤 인스턴스
export const apiCache = new ApiCacheService();

// 주기적 정리 (5분마다)
if (typeof window !== 'undefined') {
  setInterval(() => {
    apiCache.cleanup();
  }, 5 * 60 * 1000);
}

/**
 * 캐시 가능한 API 호출 래퍼
 */
export async function cachedFetch<T>(
  key: string,
  fetcher: () => Promise<T>,
  options?: CacheOptions
): Promise<T> {
  // 캐시 확인
  const cached = apiCache.get<T>(key);
  if (cached !== null) {
    console.log(`✅ [Cache HIT] ${key}`);
    return cached;
  }

  // 캐시 미스 - 데이터 로드
  console.log(`🔄 [Cache MISS] ${key}`);
  const data = await fetcher();
  
  // 캐시에 저장
  apiCache.set(key, data, options);
  
  return data;
}
