import { ConfigService } from '@nestjs/config';
import { notNilEmpty } from 'qx-util';
import { GatewayRegisterCenterService, NacosHostItem } from '../../interface';
import { logger } from '../../utils';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const NacosNamingClient = require('nacos').NacosNamingClient;

/**
 * nacos服务
 *
 * @author chitanda
 * @date 2021-08-11 11:08:54
 * @export
 * @class NacosService
 */
export class NacosService implements GatewayRegisterCenterService {
  protected static instance: NacosService;

  /**
   * nacos客户端
   *
   * @author chitanda
   * @date 2021-08-11 11:08:51
   * @type {*}
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  protected client: any;

  /**
   * 服务对应转发地址
   *
   * @author chitanda
   * @date 2021-08-12 12:08:21
   * @protected
   * @type {Map<string, string[]>}
   */
  protected address: Map<string, string[]> = new Map();

  /**
   * Creates an instance of NacosService.
   *
   * @author chitanda
   * @date 2021-08-15 18:08:43
   */
  constructor(public configService: ConfigService) {
    if (NacosService.instance) {
      return NacosService.instance;
    }
    NacosService.instance = this;
  }

  /**
   * 根据服务名称获取服务标识
   *
   * @author chitanda
   * @date 2022-04-02 10:04:08
   * @param {string} serviceName
   * @return {*}  {string}
   */
  getServiceId(serviceName: string): string {
    return this.configService.get(`gateway.${serviceName}.serviceId`);
  }

  /**
   * 根据服务名称获取对应地址
   *
   * @author chitanda
   * @date 2022-04-02 10:04:10
   * @param {string} serviceName
   * @return {*}  {string[]}
   */
  getAddress(serviceName: string): string[] {
    return this.address.get(serviceName) || [];
  }

  /**
   * 初始化nacos
   *
   * @author chitanda
   * @date 2021-08-11 11:08:21
   * @return {*}  {Promise<void>}
   */
  async init(): Promise<void> {
    const nacos = this.configService.get('nacos');
    this.client = new NacosNamingClient({
      logger,
      serverList: nacos.serverAddr,
      namespace: nacos.namespace,
      ssl: nacos.ssl
    });
    await this.client.ready();
  }

  /**
   * 注册nacos服务实例
   *
   * @author chitanda
   * @date 2021-08-12 11:08:06
   * @param {Record<string, unknown>} config
   * @return {*}  {Promise<void>}
   */
  async registerInstance(config: Record<string, unknown>): Promise<void> {
    const nacos = this.configService.get('nacos');
    await this.client.registerInstance(nacos.serviceName, config, nacos.groupName);
    this.subAllInstances();
  }

  /**
   * 订阅nacos服务实例
   *
   * @author chitanda
   * @date 2021-08-12 12:08:36
   * @protected
   */
  protected subAllInstances(): void {
    const groupName = this.configService.get('nacos.groupName');
    const NacosGateway = this.configService.get('gateway');
    const allServiceId: Set<string> = new Set();
    for (const key in NacosGateway) {
      const cfg = NacosGateway[key];
      allServiceId.add(cfg.serviceId);
    }
    const arr = Array.from(allServiceId);
    for (let i = 0; i < arr.length; i++) {
      const serviceName = arr[i];
      this.client.subscribe({ serviceName, groupName }, hosts => {
        this.calcAddress(serviceName, hosts);
      });
    }
  }

  /**
   * 计算
   *
   * @author chitanda
   * @date 2021-08-12 11:08:00
   * @protected
   * @param {string} tag
   * @param {NacosHostItem[]} hosts
   */
  protected calcAddress(tag: string, hosts: NacosHostItem[]): void {
    const arr: string[] = [];
    const protocol = this.configService.get('app.gatewayProtocol');
    if (notNilEmpty(hosts)) {
      hosts.forEach(host => {
        if (host.enabled) {
          arr.push(`${protocol}://${host.ip}:${host.port}`);
        }
      });
    }
    if (notNilEmpty(arr)) {
      this.address.set(tag, arr);
    }
  }

  /**
   * 获取唯一实例
   *
   * @author chitanda
   * @date 2021-08-15 18:08:03
   * @static
   * @return {*}  {NacosService}
   */
  static getInstance(): NacosService {
    return this.instance;
  }
}
