"use strict";

/**
 * Centralized cache utility with TTL support
 * 
 * This is a production-ready cache implementation used across the codebase
 * for consistent caching behavior and performance optimization.
 */

/**
 * Cache entry with expiration tracking
 */

/**
 * Cache statistics
 */

/**
 * TTL-based cache implementation
 * 
 * Features:
 * - Automatic expiration based on TTL
 * - Manual cleanup of expired entries
 * - Statistics tracking (hits, misses, hit rate)
 * - Type-safe generic interface
 * 
 * @example
 * ```typescript
 * const cache = new TTLCache<string>(5 * 60 * 1000); // 5 minutes
 * 
 * // Set with default TTL
 * cache.set('key', 'value');
 * 
 * // Set with custom TTL
 * cache.set('key', 'value', 10 * 60 * 1000); // 10 minutes
 * 
 * // Get value
 * const value = cache.get('key');
 * 
 * // Get statistics
 * const stats = cache.getStats();
 * ```
 */
export class TTLCache {
  cache = new Map();
  hits = 0;
  misses = 0;

  /**
   * Create a new TTL cache
   * @param defaultTTL Default TTL in milliseconds (default: 5 minutes)
   */
  constructor(defaultTTL = 5 * 60 * 1000) {
    this.defaultTTL = defaultTTL;
  }

  /**
   * Get a value from cache
   * @param key Cache key
   * @returns Cached value or null if not found or expired
   */
  get(key) {
    const entry = this.cache.get(key);
    if (!entry) {
      this.misses++;
      return null;
    }
    const now = Date.now();
    if (now > entry.expiresAt) {
      this.cache.delete(key);
      this.misses++;
      return null;
    }
    this.hits++;
    return entry.data;
  }

  /**
   * Set a value in cache
   * @param key Cache key
   * @param data Data to cache
   * @param ttl Optional TTL override (uses default if not provided)
   */
  set(key, data, ttl) {
    const now = Date.now();
    const expiresAt = now + (ttl || this.defaultTTL);
    this.cache.set(key, {
      data,
      timestamp: now,
      expiresAt
    });
  }

  /**
   * Delete a specific cache entry
   * @param key Cache key
   * @returns true if entry was deleted, false if not found
   */
  delete(key) {
    return this.cache.delete(key);
  }

  /**
   * Clear all cache entries
   */
  clear() {
    this.cache.clear();
    this.hits = 0;
    this.misses = 0;
  }

  /**
   * Check if a key exists and is not expired
   * @param key Cache key
   * @returns true if key exists and is valid
   */
  has(key) {
    const entry = this.cache.get(key);
    if (!entry) return false;
    if (Date.now() > entry.expiresAt) {
      this.cache.delete(key);
      return false;
    }
    return true;
  }

  /**
   * Get all valid cache keys
   * @returns Array of valid cache keys
   */
  keys() {
    const now = Date.now();
    const validKeys = [];
    for (const [key, entry] of this.cache.entries()) {
      if (now <= entry.expiresAt) {
        validKeys.push(key);
      } else {
        this.cache.delete(key);
      }
    }
    return validKeys;
  }

  /**
   * Clean up expired entries
   * @returns Number of entries removed
   */
  cleanup() {
    const now = Date.now();
    let removed = 0;
    for (const [key, entry] of this.cache.entries()) {
      if (now > entry.expiresAt) {
        this.cache.delete(key);
        removed++;
      }
    }
    return removed;
  }

  /**
   * Get cache size (number of entries)
   */
  size() {
    return this.cache.size;
  }

  /**
   * Get cache statistics
   */
  getStats() {
    const total = this.hits + this.misses;
    return {
      size: this.cache.size,
      hits: this.hits,
      misses: this.misses,
      hitRate: total > 0 ? this.hits / total : 0
    };
  }

  /**
   * Reset statistics (keeps cache entries)
   */
  resetStats() {
    this.hits = 0;
    this.misses = 0;
  }
}

/**
 * Create a TTL cache instance (convenience function)
 * 
 * @example
 * ```typescript
 * const cache = createCache<string>(5 * 60 * 1000);
 * ```
 */
export function createCache(ttl = 5 * 60 * 1000) {
  return new TTLCache(ttl);
}

/**
 * Global cache cleanup interval (runs every minute)
 * This helps prevent memory leaks from expired cache entries
 */
let cleanupInterval = null;
const activeCaches = new Set();

/**
 * Register a cache for automatic cleanup
 * @param cache Cache instance to register
 */
export function registerCacheForCleanup(cache) {
  activeCaches.add(cache);

  // Start cleanup interval if not already running
  if (!cleanupInterval) {
    cleanupInterval = setInterval(() => {
      for (const cache of activeCaches) {
        cache.cleanup();
      }
    }, 60000); // Every minute
  }
}

/**
 * Unregister a cache from automatic cleanup
 * @param cache Cache instance to unregister
 */
export function unregisterCacheFromCleanup(cache) {
  activeCaches.delete(cache);

  // Stop cleanup interval if no caches are registered
  if (activeCaches.size === 0 && cleanupInterval) {
    clearInterval(cleanupInterval);
    cleanupInterval = null;
  }
}

/**
 * Stop all cleanup intervals (useful for testing)
 * This will clear the interval and unregister all caches
 */
export function stopAllCleanupIntervals() {
  if (cleanupInterval) {
    clearInterval(cleanupInterval);
    cleanupInterval = null;
  }
  activeCaches.clear();
}
//# sourceMappingURL=cache.js.map