import { createClient, RedisClientType } from 'redis';
import { logger } from '../../utils/logger';

class RedisService {
  private client: RedisClientType;
  private isConnected: boolean = false;

  constructor() {
    this.client = createClient({
      url: process.env.REDIS_URL || 'redis://localhost:6379'
    });

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

    this.client.on('connect', () => {
      logger.info('[RedisService] Connected to Redis');
      this.isConnected = true;
    });

    this.client.on('end', () => {
      logger.info('[RedisService] Disconnected from Redis');
      this.isConnected = false;
    });

    this.connect();
  }

  private async connect() {
    try {
      await this.client.connect();
      this.isConnected = true;
    } catch (error) {
      logger.error(`[RedisService] Failed to connect: ${(error as any).message}`);
      this.isConnected = false;
    }
  }

  /**
   * 检查Redis连接状态
   */
  public async checkConnection(): Promise<boolean> {
    if (!this.isConnected) {
      await this.connect();
    }
    return this.isConnected;
  }

  /**
   * 设置缓存
   */
  public async set(key: string, value: any, expireSeconds?: number): Promise<boolean> {
    try {
      if (!await this.checkConnection()) {
        return false;
      }

      const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
      
      if (expireSeconds) {
        await this.client.set(key, stringValue, { EX: expireSeconds });
      } else {
        await this.client.set(key, stringValue);
      }

      return true;
    } catch (error) {
      logger.warn(`[RedisService] Failed to set key ${key}: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 获取缓存
   */
  public async get(key: string): Promise<any> {
    try {
      if (!await this.checkConnection()) {
        return null;
      }

      const value = await this.client.get(key);
      if (!value) {
        return null;
      }

      try {
        return JSON.parse(value);
      } catch {
        return value;
      }
    } catch (error) {
      logger.warn(`[RedisService] Failed to get key ${key}: ${(error as any).message}`);
      return null;
    }
  }

  /**
   * 删除缓存
   */
  public async del(key: string): Promise<boolean> {
    try {
      if (!await this.checkConnection()) {
        return false;
      }

      await this.client.del(key);
      return true;
    } catch (error) {
      logger.warn(`[RedisService] Failed to delete key ${key}: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 批量删除缓存
   */
  public async delMultiple(keys: string[]): Promise<boolean> {
    try {
      if (!await this.checkConnection() || keys.length === 0) {
        return false;
      }

      await this.client.del(keys);
      return true;
    } catch (error) {
      logger.warn(`[RedisService] Failed to delete multiple keys: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 设置哈希表字段
   */
  public async hset(key: string, field: string, value: any): Promise<boolean> {
    try {
      if (!await this.checkConnection()) {
        return false;
      }

      const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
      await this.client.hSet(key, field, stringValue);
      return true;
    } catch (error) {
      logger.warn(`[RedisService] Failed to hset key ${key}: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 获取哈希表字段
   */
  public async hget(key: string, field: string): Promise<any> {
    try {
      if (!await this.checkConnection()) {
        return null;
      }

      const value = await this.client.hGet(key, field);
      if (!value) {
        return null;
      }

      try {
        return JSON.parse(value);
      } catch {
        return value;
      }
    } catch (error) {
      logger.warn(`[RedisService] Failed to hget key ${key}: ${(error as any).message}`);
      return null;
    }
  }

  /**
   * 获取哈希表所有字段
   */
  public async hgetall(key: string): Promise<Record<string, any>> {
    try {
      if (!await this.checkConnection()) {
        return {};
      }

      const values = await this.client.hGetAll(key);
      const result: Record<string, any> = {};

      for (const [field, value] of Object.entries(values)) {
        try {
          result[field] = JSON.parse(value);
        } catch {
          result[field] = value;
        }
      }

      return result;
    } catch (error) {
      logger.warn(`[RedisService] Failed to hgetall key ${key}: ${(error as any).message}`);
      return {};
    }
  }

  /**
   * 增加计数器
   */
  public async incr(key: string): Promise<number | null> {
    try {
      if (!await this.checkConnection()) {
        return null;
      }

      return await this.client.incr(key);
    } catch (error) {
      logger.warn(`[RedisService] Failed to incr key ${key}: ${(error as any).message}`);
      return null;
    }
  }

  /**
   * 根据模式删除缓存
   */
  public async deletePattern(pattern: string): Promise<boolean> {
    try {
      if (!await this.checkConnection()) {
        return false;
      }

      const keys = await this.client.keys(pattern);
      if (keys.length > 0) {
        await this.client.del(keys);
      }
      return true;
    } catch (error) {
      logger.warn(`[RedisService] Failed to delete pattern ${pattern}: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 关闭连接
   */
  public async close(): Promise<void> {
    try {
      await this.client.disconnect();
      this.isConnected = false;
    } catch (error) {
      logger.warn(`[RedisService] Failed to close connection: ${(error as any).message}`);
    }
  }

  /**
   * Ping Redis服务器
   */
  public async ping(): Promise<string> {
    try {
      if (!await this.checkConnection()) {
        throw new Error('Redis not connected');
      }
      return await this.client.ping();
    } catch (error) {
      logger.warn(`[RedisService] Ping failed: ${(error as any).message}`);
      throw error;
    }
  }

  /**
   * 获取匹配模式的所有键
   */
  public async keys(pattern: string): Promise<string[]> {
    try {
      if (!await this.checkConnection()) {
        return [];
      }
      return await this.client.keys(pattern);
    } catch (error) {
      logger.warn(`[RedisService] Failed to get keys for pattern ${pattern}: ${(error as any).message}`);
      return [];
    }
  }

  /**
   * 关闭连接（quit别名）
   */
  public async quit(): Promise<void> {
    return this.close();
  }

  /**
   * 列表左侧推入
   */
  public async lpush(key: string, value: any): Promise<number | null> {
    try {
      if (!await this.checkConnection()) {
        return null;
      }

      const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
      return await this.client.lPush(key, stringValue);
    } catch (error) {
      logger.warn(`[RedisService] Failed to lpush key ${key}: ${(error as any).message}`);
      return null;
    }
  }

  /**
   * 列表裁剪
   */
  public async ltrim(key: string, start: number, stop: number): Promise<boolean> {
    try {
      if (!await this.checkConnection()) {
        return false;
      }

      await this.client.lTrim(key, start, stop);
      return true;
    } catch (error) {
      logger.warn(`[RedisService] Failed to ltrim key ${key}: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 获取键的TTL
   */
  public async ttl(key: string): Promise<number> {
    try {
      if (!await this.checkConnection()) {
        return -1;
      }

      return await this.client.ttl(key);
    } catch (error) {
      logger.warn(`[RedisService] Failed to get ttl for key ${key}: ${(error as any).message}`);
      return -1;
    }
  }

  /**
   * 设置键的过期时间
   */
  public async expire(key: string, seconds: number): Promise<boolean> {
    try {
      if (!await this.checkConnection()) {
        return false;
      }

      const result = await this.client.expire(key, seconds);
      return result;
    } catch (error) {
      logger.warn(`[RedisService] Failed to set expire for key ${key}: ${(error as any).message}`);
      return false;
    }
  }

  /**
   * 执行Lua脚本
   */
  public async eval(script: string, keys: string[], args: (string | number)[]): Promise<any> {
    try {
      if (!await this.checkConnection()) {
        return null;
      }

      return await this.client.eval(script, { keys, arguments: args.map(String) });
    } catch (error) {
      logger.warn(`[RedisService] Failed to eval script: ${(error as any).message}`);
      return null;
    }
  }

  /**
   * 发布消息
   */
  public async publish(channel: string, message: string): Promise<number> {
    try {
      if (!await this.checkConnection()) {
        return 0;
      }

      return await this.client.publish(channel, message);
    } catch (error) {
      logger.warn(`[RedisService] Failed to publish to channel ${channel}: ${(error as any).message}`);
      return 0;
    }
  }

  /**
   * 订阅频道
   */
  public async subscribe(channel: string, callback: (message: string) => void): Promise<void> {
    try {
      if (!await this.checkConnection()) {
        return;
      }

      const subscriber = this.client.duplicate();
      await subscriber.connect();
      await subscriber.subscribe(channel, callback);
    } catch (error) {
      logger.warn(`[RedisService] Failed to subscribe to channel ${channel}: ${(error as any).message}`);
    }
  }

  /**
   * 获取列表范围内的元素
   */
  public async lrange(key: string, start: number, stop: number): Promise<string[]> {
    try {
      if (!await this.checkConnection()) {
        return [];
      }

      return await this.client.lRange(key, start, stop);
    } catch (error) {
      logger.warn(`[RedisService] Failed to lrange key ${key}: ${(error as any).message}`);
      return [];
    }
  }

  /**
   * 设置缓存并指定过期时间 (setex 别名)
   */
  public async setex(key: string, expireSeconds: number, value: any): Promise<boolean> {
    return this.set(key, value, expireSeconds);
  }

  /**
   * 删除缓存 (del 别名)
   */
  public async delete(key: string): Promise<boolean> {
    return this.del(key);
  }
}

export default new RedisService();
