import { GatewayService } from '../../service';
import { Environment } from '@/environment';
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { createProxyMiddleware, RequestHandler } from 'http-proxy-middleware';
import { EntityPathReplace } from '@/config';
import { join } from 'path';

export class R8RedirectMiddleware {
  /**
   * nacos地址计算服务
   *
   * @author chitanda
   * @date 2021-08-17 19:08:13
   * @private
   * @type {GatewayService}
   */
  private readonly gateway: GatewayService = GatewayService.getInstance();

  /**
   * 代理实例缓存
   *
   * @author chitanda
   * @date 2022-01-20 11:01:30
   * @protected
   * @type {Map<string, RequestHandler>}
   */
  protected proxyMap: Map<string, RequestHandler> = new Map();

  use(req: any, res: any, next: () => void): void {
    let proxy: RequestHandler;
    const url = req.originalUrl.replace(`${Environment.BasePath}/`, '');
    const [path, param] = url.split('?');
    // 分割后的旧路径
    const urls: string[] = path.split('/');
    if (urls.length === 2 || urls.length === 3) {
      const [entity, _method, _id] = urls;
      // 对应服务接口名称
      const apiName = EntityPathReplace[`r8_redirect_${entity}`];
      proxy = this.getProxy(apiName);
      urls[0] = apiName;
    } else if (urls.length === 4 || urls.length === 5) {
      const [pEntity, _pEntityId, entity, _method, _id] = urls;
      const pApiName = EntityPathReplace[`r8_redirect_${pEntity}`];
      const apiName = EntityPathReplace[`r8_redirect_${entity}`];
      proxy = this.getProxy(apiName);
      urls[0] = pApiName;
      urls[2] = apiName;
    }
    const newUrl = urls.join('/') + (param ? `?${param}` : '');
    req.originalUrl = join(Environment.BasePath, Environment.DefaultAPI.Path, newUrl).replace(/\\/g, '/');
    if (proxy) {
      proxy(req, res, next);
    } else {
      next();
    }
  }

  /**
   * 获取代理对象
   *
   * @author chitanda
   * @date 2022-01-20 10:01:35
   * @protected
   * @param {string} tag
   * @return {*}  {RequestHandler}
   */
  protected getProxy(tag: string): RequestHandler {
    if (!this.proxyMap.has(tag)) {
      const host = this.getHost(tag);
      const pathKey = `^${Environment.BasePath}/`;
      const path = `/`;
      const proxy = createProxyMiddleware({
        target: host,
        changeOrigin: true,
        pathRewrite: { [pathKey]: path },
      });
      this.proxyMap.set(tag, proxy);
    }
    return this.proxyMap.get(tag);
  }

  /**
   * 从 nacos 获取服务地址
   *
   * @author chitanda
   * @date 2022-01-20 10:01:44
   * @protected
   * @param {string} tag
   * @return {*}  {(string | null)}
   */
  protected getHost(tag: string): string | null {
    if (tag) {
      const name = this.gateway.getServiceId(tag);
      const host = this.gateway.getHost(name);
      if (host) {
        return host;
      }
    }
    return null;
  }
}

/**
 * R8重定向模块
 *
 * @author chitanda
 * @date 2021-08-18 21:08:12
 * @export
 * @class R8RedirectModule
 */
@Module({})
export class R8RedirectModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    if (Environment.EnableR8APIMode) {
      const keys = Object.keys(EntityPathReplace);
      const routes = keys.map(key => `${key}/(.*)`);
      consumer.apply(R8RedirectMiddleware).forRoutes(...routes);
    }
  }
}
