import axios from "axios";
import { Message, MessageBox, Notification } from "element-ui";
import Vue from "vue";
import qs from "qs";
import { logoutHandle } from "./logout";

import GLOBAL from "../config";
import { getAuthorization } from "../plugins/crypto";
import { PLATFORM, DEVICE_ID } from "../constants/app";
import { initSyncTime, fetchTime } from "../plugins/syncServerTime";
import { objTypeOf } from "./utils";

const unNoticeUrls = ["api/admin/common/logout"];

// const IS_DEV = false;
// axios interceptors
var load = "";
// 同一时间有多个请求时，会形成队列。在第一个请求创建loading，在最后一个响应关闭loading
var queue = [];
// 设置延迟时效
axios.defaults.timeout = GLOBAL.timeout;
axios.interceptors.request.use(
  (config) => {
    // 显示loading提示
    if (!queue.length && !config.silence) {
      load = Message({
        customClass: "el-message-loading",
        iconClass: "el-message__icon el-icon-loading",
        message: "加载中...",
        duration: 0,
      });
    }
    queue.push(1);

    // 为请求头添加鉴权信息
    let token = Vue.ls.get("token");
    if (token) {
      const ids = {
        privilegeId: Vue.ls.get("privilegeId", ""),
        orgId: Vue.ls.get("orgId", ""),
        schoolId: Vue.ls.get("schoolId", ""),
        userId: Vue.ls.get("user", { id: "" }).id,
      };
      Object.entries(ids).forEach(([key, val]) => {
        if (val === null || val === "null" || val === "") return;
        config.headers[key] = val;
      });

      // 新版鉴权
      const sessionId = Vue.ls.get("user", { sessionId: "" }).sessionId;
      const timestamp = fetchTime();
      const Authorization = getAuthorization(
        {
          token: token,
          timestamp,
          account: sessionId,
          uri: config.url.split("?")[0],
          method: config.method,
        },
        "token"
      );
      config.headers["Authorization"] = Authorization;
      config.headers["time"] = timestamp;
    }
    config.headers["deviceId"] = DEVICE_ID;
    config.headers["platform"] = PLATFORM;
    config.headers["domain"] = window.location.origin;

    // if (IS_DEV) {
    //   config.headers["Authorization"] = token;
    //   config.headers["time"] = 1;
    // }
    return config;
  },
  (error) => {
    // 关闭loading提示
    // 串联并发请求，延时处理是为防止多个loading实例闪屏。
    setTimeout(() => {
      queue.shift();
      if (!queue.length) load.close();
    }, 100);
    return Promise.reject(error);
  }
);
axios.interceptors.response.use(
  (response) => {
    initSyncTime(new Date(response.headers.date).getTime());
    // 关闭loading提示
    setTimeout(() => {
      queue.shift();
      if (!queue.length) load.close();
    }, 100);
    return response;
  },
  (error) => {
    if (error.response) {
      initSyncTime(new Date(error.response.headers.date).getTime());
    }
    // 关闭loading提示
    setTimeout(() => {
      queue.shift();
      if (!queue.length) load.close();
    }, 100);
    return Promise.reject(error);
  }
);

// 防止鉴权失效之后多次弹窗。
let unauthMsgBoxIsShow = false;

const mdData = (datas) => {
  let nData = {};
  if (!datas) return nData;
  Object.entries(datas).forEach(([key, val]) => {
    if (val === null || val === "null" || val === "") return;
    nData[key] = val;
  });
  return nData;
};

/**
 * errorCallback 请求失败的回调
 * @param {Object} error 请求失败时的错误信息
 */
const errorCallback = (error) => {
  if (error.response) {
    return errorDataCallback(error.response);
  }

  if (error.request) {
    let message = "请求错误";
    if (error.message.indexOf("timeout") > -1) {
      message = "请求超时";
    }
    Notification.error({ title: "错误提示", message });
    return error;
  }

  Notification.error({ title: "错误提示", message: "请求错误" });
  return error;
};

/**
 * errorDataCallback 请求成功，结果有误的回调
 * @param {Object} response Response信息
 */
const errorDataCallback = (response) => {
  if (objTypeOf(response.data) === "blob") return response.data;

  if (unNoticeUrls.some((url) => response.config.url.includes(url))) {
    return response.data;
  }

  const error = response.data;
  let message = error.message || error.error || "请求错误";
  const unauthStatus = [401, 403];

  if (unauthStatus.includes(response.status)) {
    if (error.code === 401001 && message === "没有权限") {
      Notification.error({ title: "错误提示", message });
      return error;
    }

    if (unauthMsgBoxIsShow) return error;

    const exposeMsgs = ["系统授权信息已过期，请联系系统管理员激活!"];
    unauthMsgBoxIsShow = true;
    message = exposeMsgs.includes(message)
      ? message
      : "身份验证失效，请重新登录";
    MessageBox.confirm(message, "重新登陆?", {
      type: "warning",
      closeOnClickModal: false,
      closeOnPressEscape: false,
      showClose: false,
      callback: (action) => {
        unauthMsgBoxIsShow = false;
        if (action !== "confirm") return;

        logoutHandle();
      },
    });
  } else if (error.code === 503002) {
    Notification.error({
      title: "错误提示",
      message: "请求过于频繁，请稍后再尝试！",
    });
    return error;
  } else {
    Notification.error({ title: "错误提示", message });
  }

  return error;
};

/**
 * response format
 *  {
      config, header, data, request, status, statusText
    }
 * 
 */

/**
 * successCallback 请求成功的回调
 * @param {Object} data Response中的data信息
 */
const successCallback = (data) => {
  if (data.code === 200) {
    if (
      objTypeOf(data.data) === "object" &&
      Object.prototype.hasOwnProperty.call(data.data, "success")
    ) {
      if (data.data.success) {
        return data.data;
      } else {
        return Promise.reject(data.data);
      }
    } else {
      return data.data;
    }
  } else {
    return Promise.reject(data.data);
  }
};

/**
 * get请求
 * @param {String} url 请求地址
 * @param {Object} datas 请求数据
 */
const $get = (url, datas) => {
  return axios
    .get(url, { params: mdData(datas) })
    .then((rep) => {
      return successCallback(rep.data);
    })
    .catch((error) => {
      return Promise.reject(errorCallback(error));
    });
};

/**
 * get请求
 * @param {String} url 请求地址
 * @param {Object} datas 请求数据
 */
const $postParam = (url, datas, config = {}) => {
  return axios
    .post(
      url,
      {},
      {
        ...config,
        params: mdData(datas),
        paramsSerializer: function (params) {
          return qs.stringify(params, { arrayFormat: "repeat" });
        },
      }
    )
    .then((rep) => {
      if (config["responseType"] === "blob") return rep;

      return successCallback(rep.data);
    })
    .catch((error) => {
      return Promise.reject(errorCallback(error));
    });
};

/**
 * post请求
 * @param {String} url 请求地址
 * @param {Object} datas 请求数据
 */
const $post = (url, datas, config = {}) => {
  let sqDatas = {};
  if (datas.constructor === Object && !config["enableEmptyParam"]) {
    sqDatas = mdData(datas);
  } else {
    sqDatas = datas;
  }

  return axios
    .post(url, sqDatas, config)
    .then((rep) => {
      if (config["responseType"] === "blob") return rep;

      return successCallback(rep.data);
    })
    .catch((error) => {
      return Promise.reject(errorCallback(error));
    });
};

/**
 * delete请求
 * @param {String} url
 * @param {Object} datas
 */
const $del = (url, datas) => {
  return axios
    .delete(url, { params: mdData(datas) })
    .then((rep) => {
      return rep.data;
    })
    .catch((error) => {
      return Promise.reject(errorCallback(error));
    });
};

/**
 * put 请求
 * @param {String} url 请求地址
 * @param {Object} datas 请求数据
 */
const $put = (url, datas) => {
  return axios
    .put(url, { params: mdData(datas) })
    .then((rep) => {
      return rep.data;
    })
    .catch((error) => {
      return Promise.reject(errorCallback(error));
    });
};

/**
 * patch请求
 * @param {String} url 请求地址
 * @param {Object} datas 请求数据
 */
const $patch = (url, datas) => {
  return axios
    .patch(url, { params: mdData(datas) })
    .then((rep) => {
      return rep.data;
    })
    .catch((error) => {
      return Promise.reject(errorCallback(error));
    });
};

export { $get, $postParam, $post, $del, $put, $patch };
