import {currentRouter} from "@/framework/router";

import axios, { InternalAxiosRequestConfig, AxiosResponse } from 'axios';
import pinia from "@/framework/store";
import { useSettingsStore } from "@/framework/store/modules/settings";
import { baseRefresh } from "@/framework/api/acas";
import { getToken,setToken,removeToken,getCurrentBusinessDomain } from "@/framework/store/modules/user";

const settingsStore = useSettingsStore(pinia);

declare var window: any
// 是否正在刷新的标志
window.isRefreshing = false;
// 存储请求的数组
let cacheRequestArr: any[] = [];

// 将所有的请求都push到数组中,其实数组是[function(token){}, function(token){},...]
function cacheRequestArrHandle(cb: any) {
  cacheRequestArr.push(cb);
}
// 数组中的请求得到新的token之后自执行，用新的token去重新发起请求
function afreshRequest(token: string) {
  cacheRequestArr.map(cb => cb(token));
  cacheRequestArr = [];
}
// 判断token是否即将过期
function isTokenExpired(cToken) {
  let curTime = new Date().getTime();
  let expiresTime = cToken.expires_dt;
  //过期时间小于10分钟，进行token刷新
  if (Number(expiresTime) - curTime < 600000) {
    return true
  }
  return false;
}

function retry(config: InternalAxiosRequestConfig) {
  return new Promise<InternalAxiosRequestConfig<any>>((resolve) => {
    cacheRequestArrHandle((token: string) => {
      config.headers['Authorization'] = 'Bearer '+token; 
      resolve(config)
    })
  })
}

/**
 * 创建 axios 实例
 * 自定义属性
 * noauth: 请求不携带AccessToken,默认false
 */
const service = axios.create({
  baseURL: "/",
  timeout: 50000,
  headers: { 'Content-Type': 'application/json;charset=utf-8' },
  custom: {noauth:false}
});

/**根据配置替换后台服务名称 */
function urlServiceHandle(config){
  const serviceName=config.url.split('/')[1]
  const newServiceName=settingsStore.backendServices[serviceName]
  
  if(undefined!==newServiceName){
    config.url=config.url.replace('/'+serviceName+'/','/'+newServiceName+'/')
  }
}

/**设置Header公共参数 */
function setHeaderCommonParam(config){
  let commonParam=config.headers.commonParam
  if(undefined===commonParam)
      commonParam={}

  /**获取菜单、模块名称 */
  const cr=currentRouter()
  if(undefined!==cr.value.matched){
    if(undefined!==cr.value.matched[0]){
      commonParam.menuName=encodeURI(cr.value.matched[0].meta.title)
    }
    if(undefined!==cr.value.matched[1]){
      commonParam.moduleId=encodeURI(cr.value.matched[1].meta.id)
      commonParam.moduleName=encodeURI(cr.value.matched[1].meta.title)
    }
  }
  /**获取业务域 */
  const cbd=getCurrentBusinessDomain()
  if(undefined!==cbd.id){
    commonParam.businessDomain=cbd.id
  }
  if(undefined!==cbd.id){
    commonParam.businessDomainName=encodeURI(cbd.name)
  }

  config.headers.commonParam=JSON.stringify(commonParam)
}
/**请求配置处理 */
function requestConfigHandle(config){
  urlServiceHandle(config)//根据配置替换后台服务名称
  setHeaderCommonParam(config)//设置Header公共参数
  return config;
}

/**刷新token请求处理 */
function refreshTokenHandle(config,cToken,currentLoginType){
  let refreshTokenUrl=currentLoginType.prefixUrl+'/refreshToken'
  if (config.url === refreshTokenUrl) {
    return requestConfigHandle(config)
  }
  /**触发刷新token流程*/
  if (!window.isRefreshing) {
    window.isRefreshing = true;// 标志改为true，表示正在刷新
    baseRefresh( refreshTokenUrl, {refreshToken: cToken.refresh_token}).then((res: any) => {
      if (res.token) {
        res.token.user_type=cToken.user_type
        let newToken=setToken(res.token)
        config.headers.Authorization = newToken.access_token;
        afreshRequest(newToken.access_token) //token刷新完毕，执行队列中请求
      }else {
        ElMessage.error('获取到令牌失败')
      }
    }).finally(() => {
      window.isRefreshing = false;
    })
  }
  /**并发请求，进入队列，等待刷新token请求完成 */
  return retry(requestConfigHandle(config));
}

// 请求拦截器
service.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    if(!config.custom.noauth){
      /**Token处理 */
      const cToken=getToken()
      if (null!=cToken) {
        config.headers.Authorization = 'Bearer '+cToken.access_token;
        if (!isTokenExpired(cToken)){
          return requestConfigHandle(config)
        }
        let currentLoginType=settingsStore.loginType.find((val:any) => val.id===cToken.user_type)
        if(undefined===cToken.user_type||undefined===currentLoginType){
          ElMessage.error('当前登录类型对应配置信息不存在')
        }else{
          return refreshTokenHandle(config,cToken,currentLoginType)
        }
      }
    }
    return requestConfigHandle(config);
  },
  (error: any) => {
    return Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse) => {
    const { message, status,errorCode } = response.data;
    if (status === 200) {
      return response.data.data;
    }
    // 响应数据为二进制流处理(Excel导出)
    if (response.data.data instanceof ArrayBuffer) {
      return response.data;
    }
    if (status === 401) {
      ElMessage.error(message);
      // setTimeout(() => {
      //   removeToken()
      //   window.location.href = settingsStore.loginAddress
      // }, settingsStore.skipLoginAddressTime)
      return Promise.reject(message);
    }
    if (status === 503) {
      ElMessage.error(message || '服务繁忙');
      console.error('服务繁忙', response.data);
      return Promise.reject(message);
    }
    if (status === 429) {
      ElMessage.error(message || '请求次数过多，请稍后再试');
      console.error('请求次数过多，请稍后再试', response.data);
      return Promise.reject(message);
    }

    const temp = String(status)[0]
    if (temp === '9') {
      ElMessage.error(message || '业务异常');
      console.error('业务异常', response.data);
      return Promise.reject(message);
    }
    if (temp === '5') {
      ElMessage.error((errorCode?'['+errorCode+']':'')+'系统异常');
      console.error('系统异常', response.data);
      return Promise.reject(message);
    }

    return Promise.reject(new Error(message || 'Error'));
  },
  (error: any) => {
    if (error.response) {
      const {status} = error.response;
      if (status === 401) {
        ElMessage.error('登录失效，请重新登录');
        setTimeout(() => {
          removeToken()
          window.location.href = settingsStore.loginAddress
        }, settingsStore.skipLoginAddressTime)
        return Promise.reject('登录失效，请重新登录');
      }else if (status === 404) {
        ElMessage.error('服务不存在，请联系管理员或稍后再试');
      } else if (status === 500) {
        ElMessage.error('服务异常，请联系管理员或稍后再试');
      } else {
        ElMessage.error('服务异常');
      }
    } else {
      ElMessage.error(error.message);
    }


    return Promise.reject(error.message);
  }
);

// 导出 axios 实例
export default service;
