import { Redis } from 'ioredis';
import { logger } from './logger';

/**
 * [CORE_DEV_12] 分布式 Redis 服务
 * @description 支持集群环境下的配置热更新 (Pub/Sub)
 * 支持静态方法和实例化两种使用方式
 */
export class RedisService {
  private static client: Redis;

  /**
   * 获取Redis客户端实例
   */
  static getClient(): Redis {
    if (!this.client) {
      this.client = new Redis({
        host: process.env.REDIS_HOST || '127.0.0.1',
        port: parseInt(process.env.REDIS_PORT || '6379'),
        retryStrategy: (times) => Math.min(times * 50, 2000),
      });

      this.client.on('error', (err) => logger.error(`[Redis] Error: ${err.message}`));
    }
    return this.client;
  }

  /**
   * [CORE_DEV_12] LPush 队列
   */
  static async lPush(key: string, value: string): Promise<void> {
    try {
      await this.getClient().lpush(key, value);
    } catch (err: any) {
      logger.error(`[Redis] LPush Error: ${err.message}`);
    }
  }

  /**
   * 列表左侧推入 (别名)
   */
  static async lpush(key: string, value: string): Promise<number | null> {
    try {
      return await this.getClient().lpush(key, value);
    } catch (err: any) {
      logger.error(`[Redis] LPush Error: ${err.message}`);
      return null;
    }
  }

  /**
   * 裁剪列表
   */
  static async ltrim(key: string, start: number, stop: number): Promise<boolean> {
    try {
      await this.getClient().ltrim(key, start, stop);
      return true;
    } catch (err: any) {
      logger.error(`[Redis] LTrim Error: ${err.message}`);
      return false;
    }
  }

  /**
   * 获取列表范围
   */
  static async lrange(key: string, start: number, stop: number): Promise<string[]> {
    try {
      return await this.getClient().lrange(key, start, stop);
    } catch (err: any) {
      logger.error(`[Redis] LRange Error: ${err.message}`);
      return [];
    }
  }

  /**
   * [CORE_DEV_12] RPop 队列
   */
  static async rPop(key: string): Promise<string | null> {
    try {
      return await this.getClient().rpop(key);
    } catch (err: any) {
      logger.error(`[Redis] RPop Error: ${err.message}`);
      return null;
    }
  }

  /**
   * [CORE_DEV_12] Get 缓存
   */
  static async get(key: string): Promise<string | null> {
    try {
      return await this.getClient().get(key);
    } catch (err: any) {
      logger.error(`[Redis] Get Error: ${err.message}`);
      return null;
    }
  }

  /**
   * [CORE_DEV_12] Set 缓存
   */
  static async set(key: string, value: string, ttl?: number, mode?: 'NX' | 'XX'): Promise<string | null> {
    try {
      if (mode === 'NX') {
        if (ttl) {
          const result = await this.getClient().set(key, value, 'PX', ttl * 1000, 'NX');
          return result;
        } else {
          const result = await this.getClient().set(key, value, 'NX');
          return result;
        }
      } else if (mode === 'XX') {
        if (ttl) {
          const result = await this.getClient().set(key, value, 'PX', ttl * 1000, 'XX');
          return result;
        } else {
          const result = await this.getClient().set(key, value, 'XX');
          return result;
        }
      } else {
        if (ttl) {
          await this.getClient().setex(key, ttl, value);
          return 'OK';
        } else {
          await this.getClient().set(key, value);
          return 'OK';
        }
      }
    } catch (err: any) {
      logger.error(`[Redis] Set Error: ${err.message}`);
      return null;
    }
  }

  /**
   * 删除键
   */
  static async del(key: string): Promise<number> {
    try {
      return await this.getClient().del(key);
    } catch (err: any) {
      logger.error(`[Redis] Del Error: ${err.message}`);
      return 0;
    }
  }

  /**
   * 获取键的TTL
   */
  static async ttl(key: string): Promise<number> {
    try {
      return await this.getClient().ttl(key);
    } catch (err: any) {
      logger.error(`[Redis] TTL Error: ${err.message}`);
      return -1;
    }
  }

  /**
   * 设置键的过期时间
   */
  static async expire(key: string, seconds: number): Promise<boolean> {
    try {
      const result = await this.getClient().expire(key, seconds);
      return result === 1;
    } catch (err: any) {
      logger.error(`[Redis] Expire Error: ${err.message}`);
      return false;
    }
  }

  /**
   * 执行Lua脚本
   */
  static async eval(script: string, numKeys: number, ...args: (string | number)[]): Promise<any> {
    try {
      return await this.getClient().eval(script, numKeys, ...args);
    } catch (err: any) {
      logger.error(`[Redis] Eval Error: ${err.message}`);
      return null;
    }
  }

  /**
   * 发布消息
   */
  static async publish(channel: string, message: string): Promise<number> {
    try {
      return await this.getClient().publish(channel, message);
    } catch (err: any) {
      logger.error(`[Redis] Publish Error: ${err.message}`);
      return 0;
    }
  }

  /**
   * 订阅频道
   */
  static async subscribe(channel: string, callback: (message: string) => void): Promise<void> {
    try {
      const subClient = new Redis({
        host: process.env.REDIS_HOST || '127.0.0.1',
        port: parseInt(process.env.REDIS_PORT || '6379'),
        retryStrategy: (times) => Math.min(times * 50, 2000),
      });

      subClient.on('error', (err) => {
        logger.warn(`[Redis] Subscription client error: ${err.message}`);
      });

      await subClient.subscribe(channel);
      
      subClient.on('message', (chan, msg) => {
        if (chan === channel) {
          callback(msg);
        }
      });

      logger.info(`[Redis] Subscribed to ${channel}`);
    } catch (err: any) {
      logger.error(`[Redis] Subscribe Error: ${err.message}`);
    }
  }

  /**
   * [CORE_DEV_12] 原子增加
   */
  static async increment(key: string, amount: number = 1): Promise<number> {
    try {
      return await this.getClient().incrby(key, amount);
    } catch (err: any) {
      logger.error(`[Redis] Increment Error: ${err.message}`);
      return 0;
    }
  }

  /**
   * 发布配置变更消息
   */
  static async publishConfigChange(tenantId: string, key: string, value: any): Promise<void> {
    try {
      const channel = `config:change:${tenantId}`;
      const message = JSON.stringify({ key, value, timestamp: Date.now() });
      
      await this.getClient().publish(channel, message);
      logger.info(`[Redis] Published config change to ${channel}: ${key}`);
    } catch (err: any) {
      logger.error(`[Redis] Failed to publish config change: ${err.message}`);
    }
  }

  /**
   * [CORE_EDGE_01] 订阅状态同步消息
   */
  static async subscribeToStateSync(nodeId: string, callback: (message: any) => void): Promise<void> {
    try {
      const subClient = new Redis({
        host: process.env.REDIS_HOST || '127.0.0.1',
        port: parseInt(process.env.REDIS_PORT || '6379'),
        retryStrategy: (times) => Math.min(times * 50, 2000),
      });

      // 添加错误处理
      subClient.on('error', (err) => {
        logger.warn(`[Redis] Subscription client error: ${err.message}`);
      });

      const channel = 'edge:state:sync';
      await subClient.subscribe(channel);
      
      subClient.on('message', (chan, msg) => {
        if (chan === channel) {
          try {
            const data = JSON.parse(msg);
            if (data.sourceNode !== nodeId) {
              callback(data);
            }
          } catch (err) {
            logger.error(`[Redis] Failed to parse message: ${(err as any).message}`);
          }
        }
      });

      logger.info(`[Redis] Node ${nodeId} subscribed to ${channel}`);
    } catch (err: any) {
      logger.error(`[Redis] Failed to subscribe to state sync: ${err.message}`);
    }
  }

  /**
   * [CORE_EDGE_01] 广播本地状态变更
   */
  static async broadcastStateChange(nodeId: string, state: any): Promise<void> {
    try {
      const channel = 'edge:state:sync';
      const message = JSON.stringify({ sourceNode: nodeId, state, timestamp: Date.now() });
      
      await this.getClient().publish(channel, message);
      logger.info(`[Redis] Broadcasted state change from ${nodeId}`);
    } catch (err: any) {
      logger.error(`[Redis] Failed to broadcast state: ${err.message}`);
    }
  }

  /**
   * 获取服务状态
   */
  static async getStatus(): Promise<{ status: string; connected: boolean }> {
    try {
      await this.getClient().ping();
      return { status: 'healthy', connected: true };
    } catch (err: any) {
      return { status: 'unhealthy', connected: false };
    }
  }

  /**
   * 获取匹配模式的所有键
   */
  static async keys(pattern: string): Promise<string[]> {
    try {
      return await this.getClient().keys(pattern);
    } catch (err: any) {
      logger.error(`[Redis] Keys Error: ${err.message}`);
      return [];
    }
  }
}

export default RedisService;
