/**
 * Redis 服务 - 统一管理多个 Redis 数据库连接
 * 提供全局 Redis 客户端和会议专用 Redis 客户端
 */

import { Injectable, type OnModuleDestroy, type OnModuleInit } from '@nestjs/common';
import Redis from 'ioredis';
import { LoggerService } from '../logger/logger.service';

/**
 * Redis 数据库枚举
 */
export enum RedisDatabase {
  /** 全局业务数据库（DB 1） */
  GLOBAL = 1,
  /** 会议业务数据库（DB 0） */
  MEETING = 0,
}

/**
 * Redis 配置选项
 */
interface RedisClientOptions {
  /** 数据库编号 */
  db: RedisDatabase;
  /** 是否为生产环境 */
  isProduction?: boolean;
}

@Injectable()
export class RedisService implements OnModuleInit, OnModuleDestroy {
  /** Redis 客户端实例 Map */
  private clients = new Map<RedisDatabase, Redis>();
  /** 日志服务实例 */
  private readonly logger = new LoggerService();

  /**
   * 初始化 Redis 连接
   */
  async onModuleInit() {
    const isProduction = process.env.NODE_ENV === 'production';

    // 创建全局业务 Redis 客户端（DB 0）
    await this.createClient({
      db: RedisDatabase.GLOBAL,
      isProduction,
    });

    // 创建会议业务 Redis 客户端（DB 1）
    await this.createClient({
      db: RedisDatabase.MEETING,
      isProduction,
    });
  }

  /**
   * 创建并初始化 Redis 客户端
   */
  private async createClient(options: RedisClientOptions): Promise<void> {
    const redisConfig = {
      host: process.env.REDIS_HOST || 'localhost',
      port: Number(process.env.REDIS_PORT) || 6379,
      password: process.env.REDIS_PASSWORD || undefined,
      db: options.db,
      retryStrategy: (times: number) => {
        if (times > 10) {
          this.logger.error(`Redis DB ${options.db} 重连次数过多，放弃重连`, undefined, 'RedisService');
          return null;
        }
        const delay = Math.min(times * 100, 3000);
        this.logger.warn(`Redis DB ${options.db} ${delay}ms 后重连...`, 'RedisService');
        return delay;
      },
    };

    const client = new Redis(redisConfig);

    // 监听事件
    client.on('ready', () => {
      this.logger.info(`Redis 连接成功，数据库编号为：${options.db}${options.isProduction ? ' (生产环境)' : ' (开发环境)'}`, 'RedisService');
    });

    client.on('error', (error: Error) => {
      this.logger.error(error, `Redis DB ${options.db} 错误`, 'RedisService');
    });

    // 存储客户端
    this.clients.set(options.db, client);

    // 等待连接就绪（如果尚未就绪）
    if (client.status === 'ready') {
      return;
    }

    await new Promise<void>((resolve, reject) => {
      client.once('ready', () => resolve());
      client.once('error', reject);
    });
  }

  /**
   * 获取指定数据库的 Redis 客户端
   * @param db - 数据库编号，默认为全局数据库
   */
  getClient(db: RedisDatabase = RedisDatabase.GLOBAL): Redis {
    const client = this.clients.get(db);
    if (!client) {
      throw new Error(`Redis 客户端不存在，数据库编号：${db}`);
    }
    return client;
  }

  /**
   * 获取全局业务 Redis 客户端（DB 0）
   */
  getGlobalClient(): Redis {
    return this.getClient(RedisDatabase.GLOBAL);
  }

  /**
   * 获取会议业务 Redis 客户端（DB 1）
   */
  getMeetingClient(): Redis {
    return this.getClient(RedisDatabase.MEETING);
  }

  /**
   * 销毁模块时关闭所有 Redis 连接
   */
  async onModuleDestroy(): Promise<void> {
    const quitPromises: Array<Promise<void>> = [];

    for (const [db, client] of this.clients.entries()) {
      quitPromises.push(
        client.quit().then(() => {
          this.logger.info(`Redis DB ${db} 已关闭连接`, 'RedisService');
        })
      );
    }

    await Promise.all(quitPromises);
    this.logger.info('所有 Redis 连接已关闭', 'RedisService');
  }
}
