/**
 * Nacos 配置模块
 * 从 Nacos 配置中心加载和管理配置
 */
import { Injectable } from '@nestjs/common';
import * as nacos from 'nacos';
import * as yaml from 'js-yaml';
import { ConfigService } from '@nestjs/config';
import { LoggerService } from '../logger/logger.service';

/** 声网应用配置接口 */
export interface AgoraAppConfig {
  appId: string;
  appCertificate: string;
}

/** 声网配置接口 */
export interface AgoraConfig {
  apps: Record<string, AgoraAppConfig>;
  defaultAppId: string;
}

/**
 * Nacos 配置服务
 * 提供配置的读取和缓存功能
 */
@Injectable()
export class NacosConfigService {
  private readonly logger = new LoggerService();
  private agoraConfig: AgoraConfig | null = null;
  private configClient!: nacos.NacosConfigClient;

  constructor(private readonly configService: ConfigService) {
    this.initNacosClient();
    this.loadAgoraConfig();
  }

  /**
   * 初始化 Nacos 客户端
   */
  private initNacosClient(): void {
    const serverAddr = this.configService.get<string>('NACOS_SERVER_ADDR');
    const username = this.configService.get<string>('NACOS_USERNAME');
    const password = this.configService.get<string>('NACOS_PASSWORD');
    const namespace = this.configService.get<string>('NACOS_NAMESPACE_ID');

    if (!serverAddr) {
      throw new Error('NACOS_SERVER_ADDR 环境变量未配置');
    }

    try {
      // 创建 Nacos 配置客户端
      this.configClient = new nacos.NacosConfigClient({
        serverAddr,
        username: username || undefined,
        password: password || undefined,
        namespace: namespace || undefined,
      });

      this.logger.info(`Nacos 客户端初始化成功，服务器地址：${serverAddr}`);
    } catch (error) {
      this.logger.error('Nacos 客户端初始化失败:', error);
      throw new Error(`Nacos 客户端初始化失败：${error.message}`, { cause: error });
    }
  }

  /**
   * 从 Nacos 加载声网配置文件
   */
  private async loadAgoraConfig(): Promise<void> {
    try {
      const dataId = this.configService.get<string>('NACOS_DATA_ID');
      const group = this.configService.get<string>('NACOS_GROUP') || 'DEFAULT_GROUP';

      // 从 Nacos 获取配置内容
      const configContent = await this.configClient.getConfig(
        this.configService.get<string>('NACOS_DATA_ID')!,
        this.configService.get<string>('NACOS_GROUP') || 'DEFAULT_GROUP'
      );

      if (!configContent) {
        throw new Error(`Nacos 中未找到配置：dataId=${dataId}, group=${group}`);
      }

      // 解析 YAML 配置
      const config = yaml.load(configContent) as AgoraConfig;

      if (!config.apps || !config.defaultAppId) {
        throw new Error('Nacos 配置格式错误：必须包含 apps 和 defaultAppId 字段');
      }

      if (!config.apps[config.defaultAppId]) {
        throw new Error(`Nacos 配置错误：defaultAppId '${config.defaultAppId}' 在 apps 中不存在`);
      }

      this.agoraConfig = config;
      this.logger.info(`声网配置从 Nacos 加载成功，默认应用：${config.defaultAppId}`);

      // 监听配置变化（可选，实现热更新）
      try {
        // 使用已解析的 dataId 和 group，传入对象格式
        this.configClient.subscribe({ dataId, group }, (content: string) => {
          this.logger.info('检测到 Nacos 配置变更，重新加载...');
          try {
            const newConfig = yaml.load(content) as AgoraConfig;
            this.agoraConfig = newConfig;
            this.logger.info(`声网配置已更新，默认应用：${newConfig.defaultAppId}`);
          } catch (error) {
            this.logger.error('配置更新失败', error);
          }
        });
      } catch {
        // 配置监听失败不影响主流程，记录警告日志
        this.logger.warn('Nacos 配置监听器设置失败，但配置已成功加载');
      }
    } catch (error) {
      this.logger.error('从 Nacos 加载声网配置失败', error);
      throw new Error(`从 Nacos 加载声网配置失败：${error.message}`, { cause: error });
    }
  }

  /**
   * 获取声网配置
   * @returns {AgoraConfig} 声网配置对象
   */
  getAgoraConfig(): AgoraConfig {
    if (!this.agoraConfig) {
      throw new Error('声网配置未加载，请检查 Nacos 配置是否正确且格式有效');
    }
    return this.agoraConfig;
  }

  /**
   * 获取指定的声网应用配置
   * @param {string} appId - 应用 ID（可选，默认使用 defaultAppId）
   * @returns {AgoraAppConfig} 声网应用配置
   */
  getAgoraAppConfig(appId?: string): AgoraAppConfig {
    const agoraConfig = this.getAgoraConfig();
    const targetAppId = appId || agoraConfig.defaultAppId;

    const appConfig = agoraConfig.apps[targetAppId];
    if (!appConfig) {
      const errorMsg = `未找到声网应用配置：${targetAppId}。可用的应用 ID: ${Object.keys(agoraConfig.apps).join(', ')}`;
      this.logger.error(errorMsg);
      throw new Error(errorMsg);
    }

    return appConfig;
  }

  /**
   * 获取默认的声网应用配置
   * @returns {AgoraAppConfig} 默认声网应用配置
   */
  getDefaultAgoraAppConfig(): AgoraAppConfig {
    return this.getAgoraAppConfig();
  }
}
