const { createProxyMiddleware } = require('http-proxy-middleware');
const logger = require('./logger');

const setupProxyFeature = (app, webpackConfig) => {
  if (!Array.isArray(webpackConfig.proxy)) {
    if (Object.prototype.hasOwnProperty.call(webpackConfig.proxy, 'target')) {
      webpackConfig.proxy = [webpackConfig.proxy];
    } else {
      webpackConfig.proxy = Object.keys(webpackConfig.proxy).map(context => {
        let proxyOptions;
        // For backwards compatibility reasons.
        const correctedContext = context
          .replace(/^\*$/, '**')
          .replace(/\/\*$/, '');

        if (typeof webpackConfig.proxy[context] === 'string') {
          proxyOptions = {
            context: correctedContext,
            target: webpackConfig.proxy[context],
          };
        } else {
          proxyOptions = Object.assign({}, webpackConfig.proxy[context]);
          proxyOptions.context = correctedContext;
        }

        proxyOptions.logLevel = proxyOptions.logLevel || 'warn';

        return proxyOptions;
      });
    }
  }

  // eslint-disable-next-line consistent-return
  const getProxyMiddleware = proxyConfig => {
    const context = proxyConfig.context || proxyConfig.path;

    // It is possible to use the `bypass` method without a `target`.
    // However, the proxy middleware has no use in this case, and will fail to instantiate.
    if (proxyConfig.target) {
      return createProxyMiddleware(context, proxyConfig);
    }
  };
  /**
   * Assume a proxy configuration specified as:
   * proxy: [
   *   {
   *     context: ...,
   *     ...options...
   *   },
   *   // or:
   *   function() {
   *     return {
   *       context: ...,
   *       ...options...
   *     };
   *   }
   * ]
   */
  webpackConfig.proxy.forEach(proxyConfigOrCallback => {
    let proxyMiddleware;

    let proxyConfig =
      typeof proxyConfigOrCallback === 'function'
        ? proxyConfigOrCallback()
        : proxyConfigOrCallback;

    proxyMiddleware = getProxyMiddleware(proxyConfig);

    if (proxyConfig.ws) {
      this.websocketProxies.push(proxyMiddleware);
    }

    // eslint-disable-next-line consistent-return
    const handle = (req, res, next) => {
      if (typeof proxyConfigOrCallback === 'function') {
        const newProxyConfig = proxyConfigOrCallback();

        if (newProxyConfig !== proxyConfig) {
          proxyConfig = newProxyConfig;
          proxyMiddleware = getProxyMiddleware(proxyConfig);
        }
      }

      // - Check if we have a bypass function defined
      // - In case the bypass function is defined we'll retrieve the
      // bypassUrl from it otherwise bypassUrl would be null
      const isByPassFuncDefined = typeof proxyConfig.bypass === 'function';
      const bypassUrl = isByPassFuncDefined
        ? proxyConfig.bypass(req, res, proxyConfig)
        : null;

      if (typeof bypassUrl === 'boolean') {
        // skip the proxy
        req.url = null;
        next();
      } else if (typeof bypassUrl === 'string') {
        // byPass to that url
        req.url = bypassUrl;
        next();
      } else if (proxyMiddleware) {
        return proxyMiddleware(req, res, next);
      } else {
        next();
      }
    };

    app.use(handle);
    // Also forward error requests to the proxy so it can handle them.
    app.use((error, req, res, next) => handle(req, res, next));
  });
};

const addProxyMiddleware = app => {
  if (process.env.PROXY) {
    const proxies = process.env.PROXY.split(';');
    // 设置代理
    setupProxyFeature(app, {
      proxy: proxies.map(proxyStr => {
        const mathes = proxyStr.match(/^\s*([/\w]+)\s*:\s*(.+)\s*$/);
        return {
          path: mathes[1],
          target: mathes[2],
          changeOrigin: true,
        };
      }),
    });
  }
};

module.exports = {
  addProxyMiddleware,
};
