/**
 * Request Deduplication Middleware
 * Prevents duplicate requests for the same data within a short time window
 * Reduces database load and improves response times
 */

import NodeCache from 'node-cache';

const requestCache = new NodeCache({ 
  stdTTL: 30, // 30 seconds default TTL
  checkperiod: 10,
  useClones: false, // Better performance for large objects
  maxKeys: 1000
});

const pendingRequests = new Map();

/**
 * Request deduplication middleware
 * Caches responses and deduplicates identical requests
 */
export function requestDeduplication(req, res, next) {
  // Only for GET requests
  if (req.method !== 'GET') {
    return next();
  }
  
  // Generate cache key from path and query params
  const cacheKey = `${req.path}:${JSON.stringify(req.query)}`;
  
  // Check if request is already pending
  if (pendingRequests.has(cacheKey)) {
    console.log(`⏳ Deduplicating request: ${req.path}`);
    return pendingRequests.get(cacheKey).then(result => {
      res.set('X-Cache', 'DEDUP');
      res.json(result);
    }).catch(err => {
      // If pending request failed, let it fall through
      pendingRequests.delete(cacheKey);
      next();
    });
  }
  
  // Check cache
  const cached = requestCache.get(cacheKey);
  if (cached) {
    res.set('X-Cache', 'HIT');
    return res.json(cached);
  }
  
  // Store original json function
  const originalJson = res.json.bind(res);
  
  // Create promise for pending request
  const requestPromise = new Promise((resolve, reject) => {
    res.json = (data) => {
      // Cache the result
      requestCache.set(cacheKey, data, 30); // 30 second TTL
      pendingRequests.delete(cacheKey);
      originalJson(data);
      resolve(data);
    };
    
    // Handle errors
    const originalStatus = res.status.bind(res);
    res.status = (code) => {
      if (code >= 400) {
        pendingRequests.delete(cacheKey);
      }
      return originalStatus(code);
    };
  });
  
  pendingRequests.set(cacheKey, requestPromise);
  res.set('X-Cache', 'MISS');
  
  // Cleanup on timeout (prevent memory leaks)
  setTimeout(() => {
    if (pendingRequests.has(cacheKey)) {
      pendingRequests.delete(cacheKey);
    }
  }, 60000); // 60 second timeout
  
  next();
}

/**
 * Clear cache utility
 */
export function clearRequestCache() {
  requestCache.flushAll();
  pendingRequests.clear();
}

/**
 * Get cache statistics
 */
export function getCacheStats() {
  return {
    cache: requestCache.getStats(),
    pendingRequests: pendingRequests.size
  };
}

