// utils/cache.js - 통합 캐싱 시스템

const NodeCache = require('node-cache');

// 메모리 캐시 (Redis가 없을 때 fallback)
const memoryCache = new NodeCache({
  stdTTL: 600, // 기본 10분
  checkperiod: 120, // 2분마다 만료된 키 정리
  useClones: false // 성능 향상을 위해 복사본 생성 안함
});

// Redis 클라이언트 (선택적)
let redisClient = null;

/**
 * Redis 연결 초기화 (선택적)
 */
const initRedis = async () => {
  try {
    const redis = require('redis');
    
    redisClient = redis.createClient({
      socket: {
        host: process.env.REDIS_HOST || 'localhost',
        port: process.env.REDIS_PORT || 6379,
        reconnectStrategy: (retries) => {
          if (retries > 10) {
            console.warn('Redis 재시도 횟수 초과. 메모리 캐시를 사용합니다.');
            return false; // Redis 연결 포기
          }
          return Math.min(retries * 100, 3000);
        }
      },
      password: process.env.REDIS_PASSWORD || undefined,
      database: process.env.REDIS_DB || 0
    });

    redisClient.on('error', (err) => {
      console.warn('Redis 오류:', err.message);
      redisClient = null; // Redis 사용 중단, 메모리 캐시로 fallback
    });

    redisClient.on('connect', () => {
    });

    await redisClient.connect();
    
  } catch (error) {
    console.warn('Redis 초기화 실패, 메모리 캐시 사용:', error.message);
    redisClient = null;
  }
};

/**
 * 캐시에서 값 조회
 */
const get = async (key) => {
  try {
    if (redisClient && redisClient.isOpen) {
      const value = await redisClient.get(key);
      return value ? JSON.parse(value) : null;
    } else {
      return memoryCache.get(key) || null;
    }
  } catch (error) {
    console.warn(`캐시 조회 오류 (${key}):`, error.message);
    return null;
  }
};

/**
 * 캐시에 값 저장
 */
const set = async (key, value, ttl = 600) => {
  try {
    if (redisClient && redisClient.isOpen) {
      await redisClient.setEx(key, ttl, JSON.stringify(value));
    } else {
      memoryCache.set(key, value, ttl);
    }
    return true;
  } catch (error) {
    console.warn(`캐시 저장 오류 (${key}):`, error.message);
    return false;
  }
};

/**
 * 캐시에서 값 삭제
 */
const del = async (key) => {
  try {
    if (redisClient && redisClient.isOpen) {
      await redisClient.del(key);
    } else {
      memoryCache.del(key);
    }
    return true;
  } catch (error) {
    console.warn(`캐시 삭제 오류 (${key}):`, error.message);
    return false;
  }
};

/**
 * 패턴으로 캐시 키 삭제
 */
const delPattern = async (pattern) => {
  try {
    if (redisClient && redisClient.isOpen) {
      const keys = await redisClient.keys(pattern);
      if (keys.length > 0) {
        await redisClient.del(keys);
      }
    } else {
      const keys = memoryCache.keys();
      const matchingKeys = keys.filter(key => {
        const regex = new RegExp(pattern.replace('*', '.*'));
        return regex.test(key);
      });
      memoryCache.del(matchingKeys);
    }
    return true;
  } catch (error) {
    console.warn(`패턴 캐시 삭제 오류 (${pattern}):`, error.message);
    return false;
  }
};

/**
 * 전체 캐시 초기화
 */
const flush = async () => {
  try {
    if (redisClient && redisClient.isOpen) {
      await redisClient.flushDb();
    } else {
      memoryCache.flushAll();
    }
    return true;
  } catch (error) {
    console.warn('캐시 초기화 오류:', error.message);
    return false;
  }
};

/**
 * 캐시 통계 조회
 */
const getStats = () => {
  if (redisClient && redisClient.isOpen) {
    return {
      type: 'redis',
      connected: true,
      host: process.env.REDIS_HOST || 'localhost',
      port: process.env.REDIS_PORT || 6379
    };
  } else {
    const stats = memoryCache.getStats();
    return {
      type: 'memory',
      connected: true,
      keys: stats.keys,
      hits: stats.hits,
      misses: stats.misses,
      hitRate: stats.hits / (stats.hits + stats.misses) || 0
    };
  }
};

/**
 * 캐시 키 생성 헬퍼
 */
const createKey = (prefix, ...parts) => {
  return `${prefix}:${parts.join(':')}`;
};

/**
 * TTL 상수 정의
 */
const TTL = {
  SHORT: 60,        // 1분
  MEDIUM: 300,      // 5분
  LONG: 600,        // 10분
  HOUR: 3600,       // 1시간
  DAY: 86400        // 24시간
};

/**
 * 캐시 미들웨어 생성기
 */
const createCacheMiddleware = (keyGenerator, ttl = TTL.MEDIUM) => {
  return async (req, res, next) => {
    try {
      const cacheKey = typeof keyGenerator === 'function' 
        ? keyGenerator(req) 
        : keyGenerator;
      
      const cachedData = await get(cacheKey);
      
      if (cachedData) {
        return res.json(cachedData);
      }
      
      // 원본 res.json을 저장
      const originalJson = res.json;
      
      // res.json을 오버라이드하여 응답을 캐시에 저장
      res.json = function(data) {
        // 성공 응답만 캐시
        if (res.statusCode >= 200 && res.statusCode < 300) {
          set(cacheKey, data, ttl).then(() => {
          });
        }
        
        // 원본 응답 실행
        return originalJson.call(this, data);
      };
      
      next();
      
    } catch (error) {
      console.warn('캐시 미들웨어 오류:', error.message);
      next();
    }
  };
};

/**
 * 캐시 무효화 헬퍼
 */
const invalidateCache = {
  // 사용자 관련 캐시 무효화
  user: async (userId) => {
    await delPattern(`user:${userId}:*`);
    await delPattern('users:*');
  },
  
  // 작업자 관련 캐시 무효화
  worker: async (workerId) => {
    await delPattern(`worker:${workerId}:*`);
    await delPattern('workers:*');
  },
  
  // 프로젝트 관련 캐시 무효화
  project: async (projectId) => {
    await delPattern(`project:${projectId}:*`);
    await delPattern('projects:*');
  },
  
  // 작업 관련 캐시 무효화
  task: async (taskId) => {
    await delPattern(`task:${taskId}:*`);
    await delPattern('tasks:*');
  },
  
  // 일일 작업 보고서 관련 캐시 무효화
  dailyWorkReport: async (date) => {
    await delPattern(`daily-work-report:${date}:*`);
    await delPattern('daily-work-reports:*');
  },
  
  // 전체 캐시 무효화
  all: async () => {
    await flush();
  }
};

module.exports = {
  initRedis,
  get,
  set,
  del,
  delPattern,
  flush,
  getStats,
  createKey,
  TTL,
  createCacheMiddleware,
  invalidateCache
};
