import axios, { AxiosResponse } from "axios";
import qs from "qs";
import { openLoading, closeLoading } from "./loading";
import { openErrorMsg } from "./errorMsg";
import {
  fromUrls,
  fileUrls,
  GetUrls,
  PostUrls,
  notLoginUrls,
  baseURL,
  unAuthCode,
  successCode,
} from "./config";
import { router } from "@/router";
import { RouteName } from "@/router/config";

export * from "./urls";
export * from "./config";
export * from "./loading";
export * from "./errorMsg";

export type AuthHook = () => {
  token: string;
  userId: string;
  clear: () => void;
};
export const setAuthHook = (hook: AuthHook) => (getAuth = hook);
let getAuth: AuthHook = () => ({ token: "", userId: "0", clear: () => {} });

axios.defaults.baseURL = baseURL;

axios.interceptors.request.use(async (config) => {
  if (config.method === "get" && config.params) {
    for (const key in config.params) {
      const val = config.params[key];
      if (typeof val === "string") {
        config.params[key] = val.replaceAll(/[\[\]]/g, "").trim();
      }
    }
  }

  if (!config.url) {
    return config;
  }

  const { token, userId } = getAuth();
  if (!token && !~notLoginUrls.indexOf(config.url)) {
    router.replace({ name: RouteName.login });
    throw "用户未登录";
  }

  config.headers.token = token;
  config.headers.userid = userId;

  if (~GetUrls.indexOf(config.url)) {
    config.method = "GET";
  } else if (~PostUrls.indexOf(config.url)) {
    config.method = "POST";
    if (!config.data && config.params) {
      config.data = config.params;
    }
  }

  // 处理需要用表单上传的请求
  if (~fromUrls.indexOf(config.url)) {
    config.data = qs.stringify(config.data);
    config.headers["Content-Type"] =
      "application/x-www-form-urlencoded; charset=utf-8;";
  } else if (~fileUrls.indexOf(config.url)) {
    const fromData = new FormData();

    Object.keys(config.data).forEach((key) => {
      fromData.append(key, config.data[key]);
    });
    config.data = fromData;
    config.headers["Content-Type"] = "multipart/form-data";
  }

  openLoading(config.url);
  return config;
});

const responseInterceptor = (res: AxiosResponse<any, any>) => {
  closeLoading();
  if (!successCode.includes(res.data.code)) {
    let errMsg = res.data.msg || res.data.message;
    openErrorMsg(errMsg);

    if (
      ~unAuthCode.indexOf(res.data.code) ||
      errMsg === "token已经失效，请重新登录"
    ) {
      router.replace({ name: RouteName.login });
      getAuth().clear();
    }
    throw res.data.msg;
  }

  return res.data;
};

axios.interceptors.response.use(responseInterceptor, (error) => {
  closeLoading();
  if (error.response && error.response.data) {
    return responseInterceptor(error.response);
  } else {
    openErrorMsg(
      typeof error === "string" ? error : "请求失败，服务端发生了点小故障！"
    );
    return Promise.reject(error);
  }
});

export { axios };

export type PaggingReq<T> = T & {
  pageNum: number;
  pageSize: number;
};

export type PaggingRes<T> = T & {
  total: number;
  list: T[];
};
