/**
 * Redis缓存服务
 * @file cacheService.js
 * @description 提供高性能Redis缓存功能，优化数据访问速度
 */
const redis = require('redis');
const logger = require('../utils/logger');

/**
 * 缓存配置
 */
const CACHE_CONFIG = {
  host: process.env.REDIS_HOST || 'localhost',
  port: process.env.REDIS_PORT || 6379,
  password: process.env.REDIS_PASSWORD || '',
  db: process.env.REDIS_DB || 0,
  
  // 默认TTL配置（秒）
  ttl: {
    short: 5 * 60,        // 5分钟
    medium: 30 * 60,      // 30分钟
    long: 2 * 60 * 60,    // 2小时
    daily: 24 * 60 * 60   // 24小时
  },
  
  // 键名前缀
  prefix: 'nxxm:',
  
  // 连接配置
  connect_timeout: 10000,
  command_timeout: 5000,
  retry_unfulfilled_commands: true,
  retry_delay_on_failure: 100,
  max_retry_delay: 3000
};

/**
 * Redis缓存服务类
 */
class CacheService {
  constructor() {
    this.client = null;
    this.isConnected = false;
    this.stats = {
      hits: 0,
      misses: 0,
      errors: 0,
      totalOperations: 0
    };
  }

  /**
   * 初始化Redis连接
   */
  async init() {
    try {
      this.client = redis.createClient({
        url: `redis://${CACHE_CONFIG.host}:${CACHE_CONFIG.port}`,
        password: CACHE_CONFIG.password || undefined,
        database: CACHE_CONFIG.db,
        socket: {
          connectTimeout: CACHE_CONFIG.connect_timeout,
          commandTimeout: CACHE_CONFIG.command_timeout,
          reconnectStrategy: (retries) => {
            if (retries > 10) {
              logger.error('Redis重连次数超过限制，停止重连');
              return false;
            }
            return Math.min(retries * 100, 3000);
          }
        }
      });

      // 事件监听
      this.client.on('connect', () => {
        logger.info('Redis连接已建立');
        this.isConnected = true;
      });

      this.client.on('ready', () => {
        logger.info('Redis客户端已就绪');
      });

      this.client.on('error', (error) => {
        logger.error('Redis连接错误:', error);
        this.isConnected = false;
        this.stats.errors++;
      });

      this.client.on('end', () => {
        logger.warn('Redis连接已断开');
        this.isConnected = false;
      });

      this.client.on('reconnecting', () => {
        logger.info('正在重新连接Redis...');
      });

      // 连接到Redis
      await this.client.connect();
      
      logger.info('Redis缓存服务初始化成功');
    } catch (error) {
      logger.error('Redis缓存服务初始化失败:', error);
      this.isConnected = false;
      throw error;
    }
  }

  /**
   * 生成缓存键名
   * @param {string} key 键名
   * @param {string} namespace 命名空间
   * @returns {string} 完整键名
   */
  generateKey(key, namespace = 'default') {
    return `${CACHE_CONFIG.prefix}${namespace}:${key}`;
  }

  /**
   * 设置缓存
   * @param {string} key 键名
   * @param {*} value 值
   * @param {number} ttl 过期时间（秒）
   * @param {string} namespace 命名空间
   * @returns {boolean} 设置结果
   */
  async set(key, value, ttl = CACHE_CONFIG.ttl.medium, namespace = 'default') {
    if (!this.isConnected) {
      logger.warn('Redis未连接，缓存设置跳过');
      return false;
    }

    try {
      const fullKey = this.generateKey(key, namespace);
      const serializedValue = JSON.stringify(value);
      
      await this.client.setEx(fullKey, ttl, serializedValue);
      
      this.stats.totalOperations++;
      logger.debug(`缓存设置成功: ${fullKey}, TTL: ${ttl}s`);
      
      return true;
    } catch (error) {
      logger.error(`缓存设置失败 ${key}:`, error);
      this.stats.errors++;
      return false;
    }
  }

  /**
   * 获取缓存
   * @param {string} key 键名
   * @param {string} namespace 命名空间
   * @returns {*} 缓存值或null
   */
  async get(key, namespace = 'default') {
    if (!this.isConnected) {
      logger.warn('Redis未连接，缓存获取跳过');
      return null;
    }

    try {
      const fullKey = this.generateKey(key, namespace);
      const value = await this.client.get(fullKey);
      
      this.stats.totalOperations++;
      
      if (value === null) {
        this.stats.misses++;
        logger.debug(`缓存未命中: ${fullKey}`);
        return null;
      }
      
      this.stats.hits++;
      logger.debug(`缓存命中: ${fullKey}`);
      
      return JSON.parse(value);
    } catch (error) {
      logger.error(`缓存获取失败 ${key}:`, error);
      this.stats.errors++;
      return null;
    }
  }

  /**
   * 删除缓存
   * @param {string} key 键名
   * @param {string} namespace 命名空间
   * @returns {boolean} 删除结果
   */
  async del(key, namespace = 'default') {
    if (!this.isConnected) {
      return false;
    }

    try {
      const fullKey = this.generateKey(key, namespace);
      const result = await this.client.del(fullKey);
      
      this.stats.totalOperations++;
      logger.debug(`缓存删除: ${fullKey}, 结果: ${result}`);
      
      return result > 0;
    } catch (error) {
      logger.error(`缓存删除失败 ${key}:`, error);
      this.stats.errors++;
      return false;
    }
  }

  /**
   * 检查缓存是否存在
   * @param {string} key 键名
   * @param {string} namespace 命名空间
   * @returns {boolean} 是否存在
   */
  async exists(key, namespace = 'default') {
    if (!this.isConnected) {
      return false;
    }

    try {
      const fullKey = this.generateKey(key, namespace);
      const result = await this.client.exists(fullKey);
      
      this.stats.totalOperations++;
      return result === 1;
    } catch (error) {
      logger.error(`缓存存在检查失败 ${key}:`, error);
      this.stats.errors++;
      return false;
    }
  }

  /**
   * 设置过期时间
   * @param {string} key 键名
   * @param {number} ttl 过期时间（秒）
   * @param {string} namespace 命名空间
   * @returns {boolean} 设置结果
   */
  async expire(key, ttl, namespace = 'default') {
    if (!this.isConnected) {
      return false;
    }

    try {
      const fullKey = this.generateKey(key, namespace);
      const result = await this.client.expire(fullKey, ttl);
      
      this.stats.totalOperations++;
      return result === 1;
    } catch (error) {
      logger.error(`设置过期时间失败 ${key}:`, error);
      this.stats.errors++;
      return false;
    }
  }

  /**
   * 获取剩余过期时间
   * @param {string} key 键名
   * @param {string} namespace 命名空间
   * @returns {number} 剩余秒数，-1表示永不过期，-2表示键不存在
   */
  async ttl(key, namespace = 'default') {
    if (!this.isConnected) {
      return -2;
    }

    try {
      const fullKey = this.generateKey(key, namespace);
      const result = await this.client.ttl(fullKey);
      
      this.stats.totalOperations++;
      return result;
    } catch (error) {
      logger.error(`获取过期时间失败 ${key}:`, error);
      this.stats.errors++;
      return -2;
    }
  }

  /**
   * 清空指定命名空间的所有缓存
   * @param {string} namespace 命名空间
   * @returns {number} 删除的键数量
   */
  async clearNamespace(namespace) {
    if (!this.isConnected) {
      return 0;
    }

    try {
      const pattern = `${CACHE_CONFIG.prefix}${namespace}:*`;
      const keys = await this.client.keys(pattern);
      
      if (keys.length === 0) {
        return 0;
      }
      
      const result = await this.client.del(keys);
      
      this.stats.totalOperations++;
      logger.info(`清空命名空间 ${namespace}: 删除了 ${result} 个键`);
      
      return result;
    } catch (error) {
      logger.error(`清空命名空间失败 ${namespace}:`, error);
      this.stats.errors++;
      return 0;
    }
  }

  /**
   * 批量设置缓存
   * @param {Object} keyValuePairs 键值对
   * @param {number} ttl 过期时间
   * @param {string} namespace 命名空间
   * @returns {boolean} 设置结果
   */
  async mSet(keyValuePairs, ttl = CACHE_CONFIG.ttl.medium, namespace = 'default') {
    if (!this.isConnected) {
      return false;
    }

    try {
      const pipeline = this.client.multi();
      
      Object.entries(keyValuePairs).forEach(([key, value]) => {
        const fullKey = this.generateKey(key, namespace);
        const serializedValue = JSON.stringify(value);
        pipeline.setEx(fullKey, ttl, serializedValue);
      });
      
      await pipeline.exec();
      
      this.stats.totalOperations += Object.keys(keyValuePairs).length;
      logger.debug(`批量缓存设置成功: ${Object.keys(keyValuePairs).length} 个键`);
      
      return true;
    } catch (error) {
      logger.error('批量缓存设置失败:', error);
      this.stats.errors++;
      return false;
    }
  }

  /**
   * 批量获取缓存
   * @param {Array} keys 键名数组
   * @param {string} namespace 命名空间
   * @returns {Object} 键值对结果
   */
  async mGet(keys, namespace = 'default') {
    if (!this.isConnected) {
      return {};
    }

    try {
      const fullKeys = keys.map(key => this.generateKey(key, namespace));
      const values = await this.client.mGet(fullKeys);
      
      const result = {};
      keys.forEach((key, index) => {
        const value = values[index];
        if (value !== null) {
          try {
            result[key] = JSON.parse(value);
            this.stats.hits++;
          } catch (error) {
            logger.warn(`解析缓存值失败 ${key}:`, error);
            result[key] = null;
          }
        } else {
          result[key] = null;
          this.stats.misses++;
        }
      });
      
      this.stats.totalOperations += keys.length;
      return result;
    } catch (error) {
      logger.error('批量缓存获取失败:', error);
      this.stats.errors++;
      return {};
    }
  }

  /**
   * 缓存包装器 - 自动缓存函数结果
   * @param {string} key 缓存键
   * @param {Function} fn 异步函数
   * @param {number} ttl 过期时间
   * @param {string} namespace 命名空间
   * @returns {*} 函数结果
   */
  async wrap(key, fn, ttl = CACHE_CONFIG.ttl.medium, namespace = 'default') {
    // 首先尝试从缓存获取
    const cached = await this.get(key, namespace);
    if (cached !== null) {
      return cached;
    }

    try {
      // 缓存未命中，执行函数
      const result = await fn();
      
      // 将结果存入缓存
      await this.set(key, result, ttl, namespace);
      
      return result;
    } catch (error) {
      logger.error(`缓存包装器执行失败 ${key}:`, error);
      throw error;
    }
  }

  /**
   * 获取缓存统计信息
   * @returns {Object} 统计信息
   */
  getStats() {
    const hitRate = this.stats.totalOperations > 0 
      ? (this.stats.hits / (this.stats.hits + this.stats.misses)) * 100 
      : 0;

    return {
      ...this.stats,
      hitRate: hitRate.toFixed(2) + '%',
      isConnected: this.isConnected,
      config: {
        host: CACHE_CONFIG.host,
        port: CACHE_CONFIG.port,
        db: CACHE_CONFIG.db
      }
    };
  }

  /**
   * 获取Redis服务器信息
   * @returns {Object} 服务器信息
   */
  async getServerInfo() {
    if (!this.isConnected) {
      return null;
    }

    try {
      const info = await this.client.info();
      const memory = await this.client.info('memory');
      const stats = await this.client.info('stats');
      
      return {
        version: this.extractInfoValue(info, 'redis_version'),
        uptime: this.extractInfoValue(info, 'uptime_in_seconds'),
        memory: {
          used: this.extractInfoValue(memory, 'used_memory_human'),
          peak: this.extractInfoValue(memory, 'used_memory_peak_human'),
          fragmentation: this.extractInfoValue(memory, 'mem_fragmentation_ratio')
        },
        stats: {
          connections: this.extractInfoValue(stats, 'total_connections_received'),
          commands: this.extractInfoValue(stats, 'total_commands_processed'),
          hits: this.extractInfoValue(stats, 'keyspace_hits'),
          misses: this.extractInfoValue(stats, 'keyspace_misses')
        }
      };
    } catch (error) {
      logger.error('获取Redis服务器信息失败:', error);
      return null;
    }
  }

  /**
   * 从INFO字符串中提取值
   * @private
   */
  extractInfoValue(infoString, key) {
    const regex = new RegExp(`${key}:(.+)`);
    const match = infoString.match(regex);
    return match ? match[1].trim() : '';
  }

  /**
   * 健康检查
   * @returns {Object} 健康状态
   */
  async healthCheck() {
    try {
      if (!this.isConnected) {
        return {
          status: 'unhealthy',
          message: 'Redis连接断开',
          timestamp: new Date()
        };
      }

      // 执行简单的ping测试
      const pong = await this.client.ping();
      
      if (pong === 'PONG') {
        return {
          status: 'healthy',
          message: 'Redis连接正常',
          stats: this.getStats(),
          timestamp: new Date()
        };
      } else {
        return {
          status: 'unhealthy',
          message: 'Redis ping响应异常',
          timestamp: new Date()
        };
      }
    } catch (error) {
      logger.error('Redis健康检查失败:', error);
      return {
        status: 'unhealthy',
        message: 'Redis健康检查失败',
        error: error.message,
        timestamp: new Date()
      };
    }
  }

  /**
   * 关闭连接
   */
  async close() {
    try {
      if (this.client && this.isConnected) {
        await this.client.quit();
        logger.info('Redis连接已关闭');
      }
    } catch (error) {
      logger.error('关闭Redis连接失败:', error);
    }
  }

  /**
   * 清空所有缓存
   * @returns {boolean} 清空结果
   */
  async flushAll() {
    if (!this.isConnected) {
      return false;
    }

    try {
      await this.client.flushDb();
      logger.info('Redis缓存已清空');
      
      // 重置统计
      this.stats = {
        hits: 0,
        misses: 0,
        errors: 0,
        totalOperations: 0
      };
      
      return true;
    } catch (error) {
      logger.error('清空Redis缓存失败:', error);
      this.stats.errors++;
      return false;
    }
  }
}

/**
 * 缓存键名常量
 */
const CACHE_KEYS = {
  // 用户相关
  USER_LIST: 'users:list',
  USER_PROFILE: (id) => `users:profile:${id}`,
  USER_PERMISSIONS: (id) => `users:permissions:${id}`,
  
  // 农场相关
  FARM_LIST: 'farms:list',
  FARM_DETAIL: (id) => `farms:detail:${id}`,
  FARM_ANIMALS: (id) => `farms:animals:${id}`,
  FARM_DEVICES: (id) => `farms:devices:${id}`,
  
  // 设备相关
  DEVICE_LIST: 'devices:list',
  DEVICE_STATUS: (id) => `devices:status:${id}`,
  DEVICE_METRICS: (id) => `devices:metrics:${id}`,
  
  // 统计数据
  STATS_DASHBOARD: 'stats:dashboard',
  STATS_FARMS: 'stats:farms',
  STATS_DEVICES: 'stats:devices',
  STATS_ANIMALS: 'stats:animals',
  STATS_ALERTS: 'stats:alerts',
  
  // 系统配置
  SYSTEM_CONFIG: 'system:config',
  MENU_PERMISSIONS: 'system:menus',
  
  // 搜索结果
  SEARCH_RESULTS: (type, query) => `search:${type}:${Buffer.from(query).toString('base64')}`
};

/**
 * 高级缓存功能
 */
class AdvancedCache extends CacheService {
  /**
   * 缓存列表数据（带分页）
   * @param {string} key 基础键名
   * @param {Array} data 数据数组
   * @param {Object} pagination 分页信息
   * @param {number} ttl 过期时间
   */
  async setListData(key, data, pagination = {}, ttl = CACHE_CONFIG.ttl.medium) {
    const cacheData = {
      data,
      pagination,
      timestamp: Date.now()
    };
    
    return await this.set(key, cacheData, ttl, 'lists');
  }

  /**
   * 获取列表数据
   * @param {string} key 键名
   * @returns {Object} 列表数据和分页信息
   */
  async getListData(key) {
    const cached = await this.get(key, 'lists');
    
    if (cached && cached.data) {
      return {
        data: cached.data,
        pagination: cached.pagination || {},
        fromCache: true,
        cacheTimestamp: cached.timestamp
      };
    }
    
    return null;
  }

  /**
   * 智能缓存失效
   * @param {string} entity 实体类型
   * @param {string} operation 操作类型
   * @param {number} entityId 实体ID
   */
  async invalidateRelated(entity, operation, entityId = null) {
    const patterns = [];
    
    switch (entity) {
      case 'farm':
        patterns.push('farms:*', 'stats:*');
        if (entityId) {
          patterns.push(`farms:detail:${entityId}`, `farms:animals:${entityId}`, `farms:devices:${entityId}`);
        }
        break;
        
      case 'device':
        patterns.push('devices:*', 'stats:*');
        if (entityId) {
          patterns.push(`devices:status:${entityId}`, `devices:metrics:${entityId}`);
        }
        break;
        
      case 'animal':
        patterns.push('animals:*', 'stats:*');
        break;
        
      case 'user':
        patterns.push('users:*');
        if (entityId) {
          patterns.push(`users:profile:${entityId}`, `users:permissions:${entityId}`);
        }
        break;
        
      default:
        patterns.push('stats:*'); // 默认清理统计缓存
    }
    
    let totalDeleted = 0;
    for (const pattern of patterns) {
      const deleted = await this.clearPattern(pattern);
      totalDeleted += deleted;
    }
    
    logger.info(`智能缓存失效: ${entity}/${operation}, 清理了 ${totalDeleted} 个缓存键`);
    return totalDeleted;
  }

  /**
   * 按模式清理缓存
   * @private
   */
  async clearPattern(pattern) {
    if (!this.isConnected) {
      return 0;
    }

    try {
      const fullPattern = `${CACHE_CONFIG.prefix}${pattern}`;
      const keys = await this.client.keys(fullPattern);
      
      if (keys.length === 0) {
        return 0;
      }
      
      const result = await this.client.del(keys);
      return result;
    } catch (error) {
      logger.error(`按模式清理缓存失败 ${pattern}:`, error);
      return 0;
    }
  }
}

// 创建缓存服务实例
const cacheService = new AdvancedCache();

// 优雅关闭处理
process.on('SIGINT', async () => {
  logger.info('收到SIGINT信号，正在关闭Redis连接...');
  await cacheService.close();
  process.exit(0);
});

process.on('SIGTERM', async () => {
  logger.info('收到SIGTERM信号，正在关闭Redis连接...');
  await cacheService.close();
  process.exit(0);
});

module.exports = {
  cacheService,
  CACHE_KEYS,
  CACHE_CONFIG
};
