const {
  VITE_APP_DOMAIN,
  VITE_APP_GRAPH,
  VITE_APP_ADMIN_API,
  VITE_APP_AUTH_ADMIN_API,
  VITE_APP_PLATFORM_DOMAIN
} = import.meta.env;

import Axios, {
  AxiosInstance,
  AxiosRequestConfig,
  CustomParamsSerializer
} from "axios";
import {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig
} from "./types.d";
import authWhite from "./authWhite";
import { stringify } from "qs";
import NProgress from "../progress";
import { getToken, formatToken, removeToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
import { ElMessage } from "element-plus/es";
import router from "@/router";
// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  baseURL: VITE_APP_DOMAIN,
  // 请求超时时间
  timeout: 60000,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: params =>
      stringify(params, {
        arrayFormat: "brackets"
      })
  }
};

const tokenKey = "Token";

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /** token过期后，暂存待执行的请求 */
  private static requests = [];

  /** 防止重复刷新token */
  private static isRefreshing = false;

  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {};

  /** 保存当前Axios实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 重连原始请求 */
  private static retryOriginalRequest(config: PureHttpRequestConfig) {
    return new Promise(resolve => {
      PureHttp.requests.push((token: string) => {
        config.headers[tokenKey] = formatToken(token);
        resolve(config);
      });
    });
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    const domain = {
      "/api": "/api",
      "/backend": VITE_APP_ADMIN_API + "/backend",
      "/commonService": VITE_APP_ADMIN_API + "/commonService",
      "/graphService": VITE_APP_PLATFORM_DOMAIN + "/graphService",
      "/ocrService": VITE_APP_PLATFORM_DOMAIN + "/ocrService",
      "/algorServer": VITE_APP_PLATFORM_DOMAIN + "/algorServer",
      "/medicalData": VITE_APP_ADMIN_API + "/idcService/mechanism/medicalData",
      "/graph": VITE_APP_GRAPH,
      "/platformApi": VITE_APP_PLATFORM_DOMAIN
      // '/test': 'http://192.168.31.139:8000'
    };
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig): Promise<any> => {
        // 开启进度条动画
        NProgress.start();
        config.headers["platform"] = "Mechanism";
        const _data = config.params || config.data;
        const findReplaceDomainKey = Object.keys(domain).find(k =>
          new RegExp(`^${k}`).test(config.url)
        );
        if (
          authWhite.findIndex(v => new RegExp(`^${v}`).test(config.url)) > -1
        ) {
          console.log("authWhite", config.url, VITE_APP_AUTH_ADMIN_API);

          config.url = VITE_APP_AUTH_ADMIN_API + config.url;
        } else if (findReplaceDomainKey) {
          config.url = config.url.replace(
            new RegExp(`^${findReplaceDomainKey}`),
            domain[findReplaceDomainKey]
          );
        }

        if (typeof config.beforeRequestCallback === "function") {
          // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
          config.beforeRequestCallback(config);
          return config;
        }
        /** 请求白名单，放置一些不需要token的接口（通过设置请求白名单，防止token过期后再请求造成的死循环问题） */
        const whiteList = ["/api/auth"];
        return whiteList.some(v => config.url.indexOf(v) > -1)
          ? config
          : new Promise(resolve => {
              const data = getToken();
              if (data) {
                // const now = new Date().getTime();
                // const expired = parseInt(data.expires) - now <= 0;
                // if (expired) {
                //   if (!PureHttp.isRefreshing) {
                //     PureHttp.isRefreshing = true;
                //     // token过期刷新
                //     useUserStoreHook()
                //       .handRefreshToken({ refreshToken: data.refreshToken })
                //       .then(res => {
                //         const token = res.data.accessToken;
                //         config.headers[tokenKey] = formatToken(token);
                //         PureHttp.requests.forEach(cb => cb(token));
                //         PureHttp.requests = [];
                //       })
                //       .finally(() => {
                //         PureHttp.isRefreshing = false;
                //       });
                //   }
                //   resolve(PureHttp.retryOriginalRequest(config));
                // } else {
                /**
                 *
                config.url.indexOf("mallService") == -1
                  ? (config.headers[tokenKey] = formatToken(data.token))
                  : (config.headers[tokenKey] = "debug");
                 */

                config.headers[tokenKey] = formatToken(data.token);
                resolve(config);
                // }
              } else {
                resolve(config);
              }
            });
      },
      error => {
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        const $config = response.config;
        const { code, message } = response.data;
        // 关闭进度条动画
        NProgress.done();
        if (code === undefined) {
          return response.data;
        } else {
          switch (Number(code)) {
            case 200:
              return response.data;
            case 80002:
              return response.data;
            case 4401:
              return response.data;
            case 401:
            case 403:
              ElMessage.error(message);
              removeToken();
              router.replace("/login");
              return;
            default:
              ElMessage.error(message);
              return Promise.reject(response.data);
          }
        }
      },
      (error: PureHttpError) => {
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        // 关闭进度条动画
        NProgress.done();
        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<T> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回调
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          reject(error);
        });
    });
  }

  /** 单独抽离的post工具函数 */
  public post<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("post", url, { data: params }, config);
  }
  public put<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("put", url, { data: params }, config);
  }
  public delete<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("delete", url, { data: params }, config);
  }

  /** 单独抽离的get工具函数 */
  public get<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("get", url, params, config);
  }
}

export const request = new PureHttp();
