import axios from 'axios';
import type {
  AxiosRequestConfig,
  AxiosResponse,
  AxiosRequestHeaders,
  AxiosError,
} from 'axios';
import {
  Message,
  MessageReturn,
  Modal,
  Notification,
} from '@arco-design/web-vue';
import { initSyncTime, fetchTime } from '../utils/syncServerTime';
import { getAuthorization } from '../utils/crypto';
import { objTypeOf, pickByNotNull } from '../utils/utils';
import { useUserStore, useAppStore } from '../store';

axios.defaults.timeout = 2 * 60 * 1000;

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

let load: MessageReturn | null = null;
// 同一时间有多个请求时，会形成队列。在第一个请求创建loading，在最后一个响应关闭loading
const queue: Array<string | undefined> = [];
// 防止鉴权失效之后多次弹窗。
let unauthMsgBoxIsShow = false;

const modifyConfig = (config: AxiosRequestConfig): void => {
  const userStore = useUserStore();
  const appStore = useAppStore();

  const headers = {} as AxiosRequestHeaders;
  if (userStore.accessToken) {
    const ids = {
      privilegeId: userStore.privilegeId,
      orgId: userStore.orgInfo?.id,
      schoolId: userStore.curSchoolInfo?.id,
      userId: userStore.id,
    };
    Object.entries(pickByNotNull(ids)).forEach(([key, val]) => {
      headers[key] = val;
    });

    // 新版鉴权
    const timestamp = fetchTime();
    const Authorization = getAuthorization(
      {
        token: userStore.accessToken,
        timestamp,
        account: userStore.sessionId,
        uri: (config.url as string).split('?')[0] as string,
        method: config.method as string,
      },
      'token'
    );
    headers.Authorization = Authorization;
    headers.time = String(timestamp);
  }
  headers.deviceId = userStore.deviceId;
  headers.platform = userStore.platform;
  headers.domain = appStore.domain;

  config.url = `${appStore.domain}${config.url}`;
  config.headers = { ...(config.headers || {}), ...headers };
};

axios.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    // 显示loading提示
    if (!queue.length) {
      load = Message.loading({
        content: '加载中...',
        duration: 0,
      });
    }
    queue.push(config.url);

    modifyConfig(config);
    return config;
  },
  (error) => {
    // 关闭loading提示
    setTimeout(() => {
      queue.shift();
      if (!queue.length) load?.close();
    }, 100);

    Message.error({
      content: error.message || '请求错误',
      duration: 5 * 1000,
    });
    return Promise.reject(error);
  }
);
// add response interceptors
axios.interceptors.response.use(
  (response: AxiosResponse) => {
    initSyncTime(new Date(response.headers.date).getTime());
    // 关闭loading提示
    setTimeout(() => {
      queue.shift();
      if (!queue.length) load?.close();
    }, 100);

    if (response.config.responseType === 'blob') return response;

    return response.data.data;
  },
  (error: AxiosError) => {
    // 关闭loading提示
    setTimeout(() => {
      queue.shift();
      if (!queue.length) load?.close();
    }, 100);

    // console.dir(error);

    if (!error.response) {
      let message = error.message || '无响应错误';
      if (message.indexOf('timeout') > -1) {
        message = '响应超时';
      }
      Message.error({
        content: message,
        duration: 5 * 1000,
      });
      return Promise.reject(error);
    }

    const { response } = error;
    initSyncTime(new Date(response.headers.date).getTime());

    if (unNoticeUrls.some((url) => (response.config.url || '').includes(url))) {
      return Promise.reject(error);
    }

    if (objTypeOf(response.data) === 'blob')
      return Promise.reject(error.response.data);

    const errorData = response.data;
    let message = errorData.message || '响应未知错误';
    const unauthStatus = [401, 403];

    if (!unauthStatus.includes(response.status)) {
      Notification.error({
        title: '错误提示',
        content: message,
        closable: true,
      });
      return Promise.reject(error);
    }

    if (errorData.code === 401001 && message === '没有权限') {
      Notification.error({
        title: '错误提示',
        content: message,
        closable: true,
      });
      return Promise.reject(error);
    }

    if (unauthMsgBoxIsShow) return Promise.reject(error);

    const exposeMsgs = ['系统授权信息已过期，请联系系统管理员激活!'];
    unauthMsgBoxIsShow = true;
    message = exposeMsgs.includes(message)
      ? message
      : '身份验证失效，请重新登录！';

    Modal.confirm({
      title: '重新登陆?',
      content: message,
      escToClose: false,
      maskClosable: false,
      closable: false,
      hideCancel: true,
      titleAlign: 'start',
      onOk() {
        unauthMsgBoxIsShow = false;

        const userStore = useUserStore();
        userStore.logout();
      },
    });

    return Promise.reject(error);
  }
);
