import { createClient, RedisClientType } from 'redis';

class RedisUtil {
  private client: RedisClientType | null = null;
  private static instance: RedisUtil;

  private constructor() {}

  public static getInstance(): RedisUtil {
    if (!RedisUtil.instance) {
      RedisUtil.instance = new RedisUtil();
    }
    return RedisUtil.instance;
  }

  async connect(): Promise<RedisClientType> {
    if (!this.client) {
      this.client = createClient({
        url: process.env.REDIS_URL || 'redis://127.0.0.1:6379'
      });

      this.client.on('error', (err) => {
        console.error('Redis Client Error:', err);
      });

      await this.client.connect();
    }
    return this.client;
  }

  async disconnect(): Promise<void> {
    if (this.client) {
      await this.client.disconnect();
      this.client = null;
    }
  }

  async setSessionKey(userId: number, sessionKey: string, ttlSeconds: number = 7200): Promise<void> {
    const client = await this.connect();
    const key = `session_key:${userId}`;
    await client.set(key, sessionKey, {
      EX: ttlSeconds // 默认2小时过期，与微信session_key有效期一致
    });
  }

  async getSessionKey(userId: number): Promise<string | null> {
    const client = await this.connect();
    const key = `session_key:${userId}`;
    return await client.get(key);
  }

  async deleteSessionKey(userId: number): Promise<void> {
    const client = await this.connect();
    const key = `session_key:${userId}`;
    await client.del(key);
  }

  async isSessionKeyValid(userId: number): Promise<boolean> {
    const sessionKey = await this.getSessionKey(userId);
    return !!sessionKey;
  }

  /**
   * 设置系统配置缓存
   */
  async setSystemConfig(tenantId: number, configKey: string, configValue: string, ttlSeconds: number = 3600): Promise<void> {
    const client = await this.connect();
    const key = `system_config:${tenantId}:${configKey}`;
    await client.set(key, configValue, {
      EX: ttlSeconds // 默认1小时过期
    });
  }

  /**
   * 获取系统配置缓存
   */
  async getSystemConfig(tenantId: number, configKey: string): Promise<string | null> {
    const client = await this.connect();
    const key = `system_config:${tenantId}:${configKey}`;
    return await client.get(key);
  }

  /**
   * 删除系统配置缓存
   */
  async deleteSystemConfig(tenantId: number, configKey: string): Promise<void> {
    const client = await this.connect();
    const key = `system_config:${tenantId}:${configKey}`;
    await client.del(key);
  }

  /**
   * 批量获取系统配置缓存
   */
  async getSystemConfigs(tenantId: number, configKeys: string[]): Promise<Record<string, string | null>> {
    const client = await this.connect();
    const keys = configKeys.map(key => `system_config:${tenantId}:${key}`);
    const values = await client.mGet(keys);

    const result: Record<string, string | null> = {};
    configKeys.forEach((key, index) => {
      result[key] = values[index];
    });

    return result;
  }

  /**
   * 设置空值缓存（防止缓存穿透）
   */
  async setNullSystemConfig(tenantId: number, configKey: string, ttlSeconds: number = 300): Promise<void> {
    const client = await this.connect();
    const key = `system_config:${tenantId}:${configKey}`;
    await client.set(key, '__NULL__', {
      EX: ttlSeconds // 默认5分钟过期
    });
  }

  /**
   * 检查是否为空值缓存
   */
  isNullValue(value: string | null): boolean {
    return value === '__NULL__';
  }

  /**
   * 清除租户的所有系统配置缓存
   */
  async clearTenantSystemConfigs(tenantId: number): Promise<void> {
    const client = await this.connect();
    const pattern = `system_config:${tenantId}:*`;

    // 使用SCAN命令遍历匹配的键并删除
    let cursor = 0;
    do {
      const result = await client.scan(cursor, {
        MATCH: pattern,
        COUNT: 100
      });

      cursor = result.cursor;
      const keys = result.keys;

      if (keys.length > 0) {
        await client.del(keys);
      }
    } while (cursor !== 0);
  }

  /**
   * 格式化系统配置缓存键
   */
  formatSystemConfigKey(tenantId: number, configKey: string): string {
    return `system_config:${tenantId}:${configKey}`;
  }

  /**
   * 设置微信access_token缓存（支持租户隔离）
   * @param appId 微信小程序appId
   * @param accessToken access_token值
   * @param expiresIn 过期时间（秒），微信返回的expires_in，默认7100秒（比微信的7200秒少100秒，确保安全）
   * @param tenantId 租户ID，可选，用于多租户隔离
   */
  async setWechatAccessToken(appId: string, accessToken: string, expiresIn: number = 7100, tenantId?: number): Promise<void> {
    const client = await this.connect();
    const key = tenantId !== undefined
      ? `wechat_access_token:${tenantId}:${appId}`
      : `wechat_access_token:${appId}`;
    await client.set(key, accessToken, {
      EX: expiresIn
    });
    console.debug(`微信access_token缓存设置成功，appId: ${appId}, 租户ID: ${tenantId || '无'}, 过期时间: ${expiresIn}秒`);
  }

  /**
   * 获取微信access_token缓存（支持租户隔离）
   * @param appId 微信小程序appId
   * @param tenantId 租户ID，可选，用于多租户隔离
   * @returns access_token值或null
   */
  async getWechatAccessToken(appId: string, tenantId?: number): Promise<string | null> {
    const client = await this.connect();
    const key = tenantId !== undefined
      ? `wechat_access_token:${tenantId}:${appId}`
      : `wechat_access_token:${appId}`;
    const token = await client.get(key);

    if (token) {
      console.debug(`从缓存获取微信access_token成功，appId: ${appId}, 租户ID: ${tenantId || '无'}`);
    } else {
      console.debug(`缓存中未找到微信access_token，appId: ${appId}, 租户ID: ${tenantId || '无'}`);
    }

    return token;
  }

  /**
   * 删除微信access_token缓存（支持租户隔离）
   * @param appId 微信小程序appId
   * @param tenantId 租户ID，可选，用于多租户隔离
   */
  async deleteWechatAccessToken(appId: string, tenantId?: number): Promise<void> {
    const client = await this.connect();
    const key = tenantId !== undefined
      ? `wechat_access_token:${tenantId}:${appId}`
      : `wechat_access_token:${appId}`;
    await client.del(key);
    console.debug(`删除微信access_token缓存成功，appId: ${appId}, 租户ID: ${tenantId || '无'}`);
  }

  /**
   * 检查微信access_token缓存是否有效（支持租户隔离）
   * @param appId 微信小程序appId
   * @param tenantId 租户ID，可选，用于多租户隔离
   * @returns 是否有效
   */
  async isWechatAccessTokenValid(appId: string, tenantId?: number): Promise<boolean> {
    const token = await this.getWechatAccessToken(appId, tenantId);
    return !!token;
  }

  /**
   * 获取微信access_token缓存的剩余生存时间（支持租户隔离）
   * @param appId 微信小程序appId
   * @param tenantId 租户ID，可选，用于多租户隔离
   * @returns 剩余时间（秒），-1表示永不过期，-2表示键不存在
   */
  async getWechatAccessTokenTTL(appId: string, tenantId?: number): Promise<number> {
    const client = await this.connect();
    const key = tenantId !== undefined
      ? `wechat_access_token:${tenantId}:${appId}`
      : `wechat_access_token:${appId}`;
    return await client.ttl(key);
  }

  /**
   * 清除所有微信access_token缓存
   * @param tenantId 租户ID，可选，如果提供则只清除该租户的缓存
   */
  async clearAllWechatAccessTokens(tenantId?: number): Promise<void> {
    const client = await this.connect();
    const pattern = tenantId !== undefined
      ? `wechat_access_token:${tenantId}:*`
      : `wechat_access_token:*`;

    // 使用SCAN命令遍历匹配的键并删除
    let cursor = 0;
    do {
      const result = await client.scan(cursor, {
        MATCH: pattern,
        COUNT: 100
      });

      cursor = result.cursor;
      const keys = result.keys;

      if (keys.length > 0) {
        await client.del(keys);
        console.debug(`批量删除微信access_token缓存，数量: ${keys.length}, 租户ID: ${tenantId || '所有'}`);
      }
    } while (cursor !== 0);

    console.debug(`微信access_token缓存已清除，租户ID: ${tenantId || '所有'}`);
  }
}

export const redisUtil = RedisUtil.getInstance();