/**
 * Cache System - Stale-While-Revalidate
 *
 * Mantém dados em memória com TTL e atualização periódica.
 * Retorna dados do cache imediatamente enquanto atualiza em background.
 */

const cache = new Map();
const refreshIntervals = new Map();

const DEFAULT_TTL = 5 * 60 * 1000; // 5 minutos
const REFRESH_INTERVAL = 5 * 60 * 1000; // Atualiza a cada 5 minutos

/**
 * Armazena valor no cache
 * @param {string} key - Chave do cache
 * @param {any} value - Valor a armazenar
 * @param {number} ttl - Time-to-live em ms (opcional)
 */
function set(key, value, ttl = DEFAULT_TTL) {
  cache.set(key, {
    value,
    timestamp: Date.now(),
    ttl
  });
  console.log(`[Cache] SET ${key} (TTL: ${ttl/1000}s)`);
}

/**
 * Recupera valor do cache
 * @param {string} key - Chave do cache
 * @returns {any|null} - Valor ou null se não encontrado/expirado
 */
function get(key) {
  const entry = cache.get(key);
  if (!entry) return null;

  const age = Date.now() - entry.timestamp;
  const isStale = age > entry.ttl;

  if (isStale) {
    console.log(`[Cache] STALE ${key} (age: ${Math.round(age/1000)}s)`);
  }

  return {
    value: entry.value,
    isStale,
    age: Math.round(age / 1000)
  };
}

/**
 * Verifica se cache existe (mesmo que stale)
 */
function has(key) {
  return cache.has(key);
}

/**
 * Remove do cache
 */
function del(key) {
  cache.delete(key);
  if (refreshIntervals.has(key)) {
    clearInterval(refreshIntervals.get(key));
    refreshIntervals.delete(key);
  }
}

/**
 * Limpa todo o cache
 */
function clear() {
  cache.clear();
  refreshIntervals.forEach(interval => clearInterval(interval));
  refreshIntervals.clear();
}

/**
 * Registra função para refresh periódico
 * @param {string} key - Chave do cache
 * @param {Function} fetchFn - Função async que busca os dados
 * @param {number} interval - Intervalo de refresh em ms
 */
function registerAutoRefresh(key, fetchFn, interval = REFRESH_INTERVAL) {
  // Limpa interval anterior se existir
  if (refreshIntervals.has(key)) {
    clearInterval(refreshIntervals.get(key));
  }

  // Função de refresh
  const refresh = async () => {
    try {
      console.log(`[Cache] REFRESH ${key}`);
      const value = await fetchFn();
      set(key, value);
    } catch (err) {
      console.error(`[Cache] REFRESH ERROR ${key}:`, err.message);
    }
  };

  // Faz refresh inicial
  refresh();

  // Agenda refreshes periódicos
  const intervalId = setInterval(refresh, interval);
  refreshIntervals.set(key, intervalId);

  console.log(`[Cache] AUTO-REFRESH registered for ${key} (every ${interval/1000}s)`);
}

/**
 * Helper: get-or-fetch com stale-while-revalidate
 * Retorna cache (mesmo stale) imediatamente e atualiza em background se stale
 */
async function getOrFetch(key, fetchFn, ttl = DEFAULT_TTL) {
  const cached = get(key);

  if (cached) {
    // Se stale, atualiza em background
    if (cached.isStale) {
      fetchFn().then(value => set(key, value, ttl)).catch(err => {
        console.error(`[Cache] Background fetch error for ${key}:`, err.message);
      });
    }
    return cached.value;
  }

  // Não tem cache, busca e aguarda
  const value = await fetchFn();
  set(key, value, ttl);
  return value;
}

/**
 * Smart TTL para queries com date range:
 * - end date > 10 dias atrás → dados imutáveis → TTL 24h
 * - end date recente → dados mudam → TTL curto (5 min)
 */
const IMMUTABLE_TTL = 24 * 60 * 60 * 1000; // 24h
const FRESH_TTL = 5 * 60 * 1000; // 5 min
const STALE_DAYS = 10;

function getDateRangeTTL(endDate) {
  const end = new Date(endDate + 'T23:59:59');
  const cutoff = new Date();
  cutoff.setDate(cutoff.getDate() - STALE_DAYS);
  return end < cutoff ? IMMUTABLE_TTL : FRESH_TTL;
}

/**
 * Cache-aware fetch para queries com date range.
 * Key = prefix + start + end. TTL automático baseado na idade dos dados.
 */
async function getOrFetchRange(prefix, start, end, fetchFn) {
  const key = `${prefix}:${start}:${end}`;
  const ttl = getDateRangeTTL(end);
  return getOrFetch(key, fetchFn, ttl);
}

/**
 * Stats do cache
 */
function stats() {
  const entries = [];
  cache.forEach((entry, key) => {
    const age = Date.now() - entry.timestamp;
    entries.push({
      key,
      age: Math.round(age / 1000),
      ttl: entry.ttl / 1000,
      isStale: age > entry.ttl
    });
  });
  return {
    size: cache.size,
    entries
  };
}

module.exports = {
  set,
  get,
  has,
  del,
  clear,
  registerAutoRefresh,
  getOrFetch,
  getOrFetchRange,
  getDateRangeTTL,
  stats
};
