const NodeCache = require('node-cache');
const logger = require('../utils/logger');

// Initialize cache with default TTL of 5 minutes and check period of 2 minutes
const cache = new NodeCache({ stdTTL: 300, checkperiod: 120 });

/**
 * Cache middleware factory
 * @param {number} ttlSeconds - Time to live in seconds for cached responses
 * @returns {Function} Express middleware function
 */
const getCacheMiddleware = (ttlSeconds) => (req, res, next) => {
  // Disable caching in test environment to avoid cross-test interference
  if (process.env.NODE_ENV === 'test') {
    return next();
  }

  const key = req.originalUrl;
  const cachedResponse = cache.get(key);

  if (cachedResponse) {
    logger.info(`Cache hit for key: ${key}`);
    return res.json(cachedResponse);
  }

  logger.info(`Cache miss for key: ${key}`);
  
  // Store the original res.json method
  const originalJson = res.json.bind(res);
  
  // Override res.json to cache the response
  res.json = (body) => {
    cache.set(key, body, ttlSeconds);
    return originalJson(body);
  };
  
  next();
};

/**
 * Invalidate cache by exact key(s)
 * @param {string|string[]} keys - Cache key or array of keys to invalidate
 */
const invalidateCache = (keys) => {
  if (Array.isArray(keys)) {
    keys.forEach(key => {
      logger.info(`Invalidating cache for key: ${key}`);
      cache.del(key);
    });
  } else {
    logger.info(`Invalidating cache for key: ${keys}`);
    cache.del(keys);
  }
};

/**
 * Invalidate all cache keys matching a pattern
 * @param {string} pattern - Pattern to match (keys starting with this string)
 */
const invalidateCacheByPattern = (pattern) => {
  const keys = cache.keys();
  const keysToDelete = keys.filter(key => key.startsWith(pattern));
  
  if (keysToDelete.length > 0) {
    logger.info(`Invalidating cache by pattern: ${pattern}, deleted ${keysToDelete.length} keys`);
    cache.del(keysToDelete);
  } else {
    logger.debug(`No cache keys found matching pattern: ${pattern}`);
  }
};

/**
 * Get cache statistics
 * @returns {Object} Cache statistics
 */
const getCacheStats = () => {
  const stats = cache.getStats();
  const keys = cache.keys();
  
  return {
    keys: keys.length,
    hits: stats.hits,
    misses: stats.misses,
    hitRate: stats.hits > 0 ? (stats.hits / (stats.hits + stats.misses) * 100).toFixed(2) + '%' : '0%',
    ksize: stats.ksize,
    vsize: stats.vsize
  };
};

/**
 * Clear all cache
 */
const clearCache = () => {
  const keyCount = cache.keys().length;
  cache.flushAll();
  logger.info(`Cleared all cache (${keyCount} keys)`);
};

module.exports = {
  getCacheMiddleware,
  invalidateCache,
  invalidateCacheByPattern,
  getCacheStats,
  clearCache
};
