/*
 * @Author: Gui
 * @Date: 2023-03-01 19:20:44
 * @LastEditors: guicheng 1625811865@qq.com
 * @LastEditTime: 2024-04-16 16:39:24
 * @Description: tel files
 * @filePath:
 */
import Axios, {
  AxiosInstance,
  AxiosRequestConfig,
  CustomParamsSerializer
} from "axios";
import {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig
} from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
import { getConfig } from "@/config";
import { getToken, formatToken, removeToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
import { ElMessage } from "element-plus";
import encryptByDES from "@/utils/encryptByDES";
import regExpTest from "@/utils/FilterSensitiveWords";
import { storageLocal, storageSession, toggleClass } from "@pureadmin/utils";
import { useAppStoreHook } from "@/store/modules/app";
import router, { resetRouter } from "@/router";
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { routerArrays } from "@/layout/types";
import { dataResult } from "@/api/apiResult";

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  // 请求超时时间
  timeout: 500000,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer
  }
};

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["Authorization"] = formatToken(token);
        resolve(config);
        return config;
      });
    });
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig) => {
        // 开启进度条动画
        NProgress.start();
        // 优先判断post/get等方法是否传入回掉，否则执行初始化设置等回掉
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback(config);
          return config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback(config);
          return config;
        }
        /** 请求白名单，放置一些不需要token的接口（通过设置请求白名单，防止token过期后再请求造成的死循环问题） */
        const whiteList = ["/refreshtoken", "/login"];
        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过期刷新
                  // apiToken
                  // apiTokenExpiredDate
                  // refreshToken
                  useUserStoreHook()
                    .handRefreshToken({ refreshToken: data.refreshToken })
                    .then(res => {
                      const token = res.data.apiToken;
                      config.headers["Authorization"] = formatToken(token);
                      PureHttp.requests.forEach(cb => cb(token));
                      PureHttp.requests = [];
                    })
                    .finally(() => {
                      PureHttp.isRefreshing = false;
                    });
                }
                resolve(PureHttp.retryOriginalRequest(config));
              } else {
                config.headers["Authorization"] = formatToken(
                  data.accessToken
                );
                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;
        // 关闭进度条动画
        NProgress.done();
        // 优先判断post/get等方法是否传入回掉，否则执行初始化设置等回掉
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return response.data;
        }
        return response.data;
      },
      (error: PureHttpError) => {
        if (error.response.status === 401) {
          ElMessage({
            message: `用户token失效，请重新登录`,
            type: "error"
          });
          setTimeout(() => {
            removeToken();
            storageLocal().clear();
            storageSession().clear();
            const { Grey, Weak, Layout } = getConfig();
            useAppStoreHook().setLayout(Layout);
            toggleClass(Grey, "html-grey", document.querySelector("html"));
            toggleClass(Weak, "html-weakness", document.querySelector("html"));
            resetRouter();
            router.push("/login");
            useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
          }, 2000);
        }
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        // 关闭进度条动画
        NProgress.done();
        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error);
      }
    );
  }

  /** 登录请求工具函数 */
  public login<T>(
    url: string,
    param?: any,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<T> {
    //本地调试配置
    url = url.replace("http://localhost:5800", "/aapi")
    const config = {
      method: "post",
      url:
        url +
        "?scope=server&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer",
      data: encryptByDES(JSON.stringify(param)),
      auth: {
        username: "admin",
        password: "kmdlqkyuvl"
      },
      headers: {
        "Content-Type": "application/json"
      },
      ...axiosConfig
    } as PureHttpRequestConfig;
    // 单独处理自定义请求/响应回掉
    return new Promise((resolve, reject) => {
      console.log(
        "[ 请求地址 ] >",
        url +
        "?scope=server&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer"
      );
      console.log("[ 加密前 ] >", param);
      console.log("[ 加密后 ] >", encryptByDES(JSON.stringify(param)));
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          reject(error);
        });
    });
  }

  /** 通用请求工具函数 */
  public request(
    method: RequestMethods,
    url: string,
    param?: any,
    axiosConfig?: PureHttpRequestConfig
  ): any {
    //本地调试配置
    url = url.replace("http://localhost:5800", "/aapi")
    const config = {
      method,
      url,
      ...param,
      headers: {
        "Content-Type": "application/json"
      },
      ...axiosConfig
    } as PureHttpRequestConfig;
    // 单独处理自定义请求/响应回掉
    // console.log(config);
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          reject(error);
        });
    });
  }

  /** 单独抽离的post工具函数 */
  public post<T>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): any {
    let legal = true;
    const paramskey = [];
    for (const key in params) {
      if (
        params[key] &&
        typeof params[key] === "string" &&
        regExpTest(params[key])
      ) {
        paramskey.push(key);
        legal = false;
      }
    }
    if (legal) {
      const param = { data: encryptByDES(JSON.stringify(params)) };
      return this.request("post", url, param, config);
    } else {
      ElMessage({
        message: `params is illegal`,
        type: "error"
      });
      return Promise.reject(`${paramskey.join("、")} is illegal params`);
    }
  }
  /** 单独抽离的post工具函数 */
  public Richpost<T>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): any {
    const param = { data: encryptByDES(JSON.stringify(params)) };
    return this.request("post", url, param, config);
  }

  /** 单独抽离的get工具函数 */
  public get<T>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): any {
    let legal = true;
    const paramskey = [];
    for (const key in params) {
      if (
        params[key] &&
        typeof params[key] === "string" &&
        regExpTest(params[key])
      ) {
        paramskey.push(key);
        legal = false;
      }
    }
    if (legal) {
      console.log("[ 请求地址 ] >", url);
      console.log("[ 加密前 ] >", params);
      const paramter = { value: encryptByDES(JSON.stringify(params)) };
      const param = { params: paramter };
      console.log("[ 加密后 ] >", paramter);
      return this.request("get", url, param, config);
    } else {
      ElMessage({
        message: `params is illegal`,
        type: "error"
      });
      return Promise.reject(`${paramskey.join("、")} is illegal params`);
    }
  }
  /** 单独抽离的put工具函数 */
  public put<T>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): any {
    let legal = true;
    const paramskey = [];
    console.log('dddd', params);
    for (const key in params) {
      if (
        params[key] &&
        typeof params[key] === "string" &&
        regExpTest(params[key])
      ) {
        paramskey.push(key);
        legal = false;
      }
    }
    if (legal) {
      const param = { data: encryptByDES(JSON.stringify(params)) };
      return this.request("put", url, param, config);
    } else {
      ElMessage({
        message: `params is illegal`,
        type: "error"
      });
      return Promise.reject(`${paramskey.join("、")} is illegal params`);
    }
  }
  /** 单独抽离的delete工具函数 */
  public delete<T>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): dataResult {
    const param = { data: {} };
    console.log('ddd', params);
    return this.request(
      "delete",
      `${url}/${encryptByDES(params)}`,
      param,
      config
    );
  }
  public Request(param: any): dataResult {
    const method = param.method.toUpperCase();
    switch (method) {
      case "GET":
        return this.get(param.url, param.params, param.config);
        break;
      case "POST":
        return this.post(param.url, param.params, param.config);
        break;
      case "DELETE":
        return this.delete(param.url, param.params, param.config);
        break;
      case "PUT":
        return this.put(param.url, param.params, param.config);
        break;
      case "RICHPOST":
        return this.Richpost(param.url, param.params, param.config);
        break;
    }
  }
}

export const http = new PureHttp();
