import axios from "axios";
import qs from "qs";
// import store from '@/store'
import VueCookie from "vue-cookie";
// message消息弹窗，可自行引入其他插件
import { Toast } from "vant";
// 全局配置文件
import CONFIG from "@/config";
const { env, armsPid } = CONFIG;

const arms = process.client && !CONFIG.private ? require('@/utils/arms') : null

const logger = arms && arms(armsPid, true);

// 环境变量

// 创建axios实例，不污染axios全局
const axiosService = axios.create();

// 默认content-type
axiosService.defaults.headers["Content-Type"] = "application/x-www-form-urlencoded";
// 默认baseURL
axiosService.defaults.baseURL = CONFIG.defDomain;
// 默认请求超时时间
axiosService.defaults.timeout = 3 * 1000;

// 请求拦截器
axiosService.interceptors.request.use(
  config => {
    const token = VueCookie.get(CONFIG.tokenKey);
    const { method, headers } = config;
    const data = filterNull(config.data);
    // 格式化序列，目前只对post进行处理，可新增其他请求逻辑
    if (
      method === "post" &&
      headers["Content-Type"].includes("application/x-www-form-urlencoded")
    ) {
      config.data = qs.stringify(data);
    } else if (method === "get") {
      // 可以在调用的时候直接使用data而不用区分get(parms) post(data)
      config.params = data;
      config.data = null;
      // config.data = { unused: 0 } // axios内部处理了get方法，使data无效
    }
    // 自定义header键：token
    if (token && process.client) {
      config.headers.token = token;
    }
    // 自定义header键：X-Ca-Stage(环境变量)
    if (env) {
      config.headers["X-Ca-Stage"] = env;
    }
    config.metadata = { startTime: new Date() };
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

// 响应拦截器
axiosService.interceptors.response.use(
  response => {
    // 如果返回的状态码为200，说明接口请求成功，可以正常拿到数据
    // 否则的话抛出错误
    response.config.metadata.endTime = new Date();
    response.duration = (response.config?.metadata?.endTime || 0) - (response.config?.metadata?.startTime || 0);
    const { status, statusText, duration, data, config } = response;
    if (status === 200) {
      // console.log(data && data.errorCode === 0 && data.code === 200);
      if (data && data.errorCode === 0 && data.code === 200) {
        // success
      } else {
        // failed
        logger && logger.api(config.url, true, duration, data.errorCode, data.errorMessage);
      }
      return Promise.resolve(response.data);
    } else {
      // failed
      logger && logger.api(config.url, false, duration, status, statusText);
      errorHandle(502);
      return Promise.reject(response);
    }
  },
  error => {
    error.config.metadata.endTime = new Date();
    error.duration = (error.config?.metadata?.endTime || 0) - (error.config?.metadata?.startTime || 0);
    const { message, duration, config } = error;
    if (message.includes("timeout")) {
      // url, false, time, res.data.Flag, res.data.FlagString
      logger && logger.api(config.url, false, duration, "NetworkTimeout", message);
      errorHandle(408);
    } else {
      logger && logger.api(config.url, false, duration, "NetworkError", message);
      errorHandle(504);
    }
    return Promise.reject(error);
  }
);

/**
 * 用来判断值类型
 * @param {Object} obj
 */
function toType(obj) {
  return {}.toString
    .call(obj)
    .match(/\s([a-zA-Z]+)/)[1]
    .toLowerCase();
}

/**
 * 对象null值过滤
 * @param {Object} o 请求data对象
 */
function filterNull(o) {
  for (const key in o) {
    if (o[key] === null) {
      delete o[key];
    } else {
      // eslint-disable-next-line no-lonely-if
      if (toType(o[key]) === "string") {
        o[key] = o[key].trim();
      } else if (toType(o[key]) === "object") {
        o[key] = filterNull(o[key]);
      } else if (toType(o[key]) === "array") {
        o[key] = filterNull(o[key]);
      }
    }
  }
  return o;
}

/**
 * 根据状态码判断请求失败后的错误统一处理
 * @param {Number} status 请求失败的状态码
 */
function errorHandle(status) {
  let message = "";
  switch (status) {
    case 401:
      // 401: 未登录
      // 未登录则跳转登录页面，并携带当前页面的路径
      // 在登录成功后返回当前页面，这一步需要在登录页操作。
      message = "未授权(401)，请重新登录";
      // store.dispatch('info/jumpToLogin')
      break;
    case 403:
      // 403 token过期
      // 登录过期对用户进行提示
      // 清除本地token和清空vuex中token对象
      // 跳转登录页面
      message = "拒绝访问(403)，请刷新后重试";
      // 清除token
      // removeCookie()
      // setTimeout(() => {
      //   store.dispatch('info/jumpToLogin')
      // }, 1000)
      break;
    case 400:
      message = "请求错误（400），请刷新后重试";
      break;
    case 404:
      message = "请求错误（404），网络请求不存在";
      break;
    case 408:
      message = "请求超时(408)，请稍后重试";
      break;
    case 450:
      message = "请求异常（450），请求参数错误";
      break;
    case 500:
      message = "服务错误（500），请稍后重试！";
      break;
    case 502:
      message = "网络错误(502)，请稍后重试！";
      break;
    case 503:
      message = "服务异常（503），正在维护，请稍等！";
      break;
    case 504:
      message = "网络超时(504)，请检查网络！";
      break;
    case 505:
      message = "HTTP版本不受支持(505)";
      break;
    default:
      message = `请求失败（${status}），请检查网络或联系管理员！`;
  }
  // console.log(message);
  Toast.fail(message);
}

/**
 * request
 * @param {Object} config
 * get、delete、head、options
 * @param {String} url
 * @param {Object} config
 * post、put、patch
 * @param {String} url
 * @param {Object} data
 * @param {Object} config
 * 如果请求中需要使用与默认值不同的配置，直接传入config覆盖即可
 */
export const { get, post, delete: del, put, request, head, options, patch } = axiosService;

export default axiosService;
