import axios from 'axios'
import {Message} from 'element-ui'
import $store from '@/store'
import router from '@/router/router.js'
import store from '@/store/login'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {saveAs} from 'file-saver'

axios.defaults.timeout = 100000

let pending = [] //声明一个数组用于存储每个ajax请求的取消函数和ajax标识
let cancelToken = axios.CancelToken
let removePending = (ever) => {
  for (let p in pending) {
    if (pending[p].u === ever.url + '&' + ever.method && pending[p].data === eval.data) { //当当前请求在数组中存在时执行函数体
      pending[p].f() //执行取消操作
      pending.splice(p, 1) //把这条记录从数组中移除
    }
  }
}

// 请求拦截（配置发送请求的信息）
axios.interceptors.request.use(config => { // 处理请求之前的配置
  NProgress.start() //开始
  store.state.loadding = true //在请求发出之前进行一些操作
  config.headers = config.headers || {}
  if (config.headers && config.headers.constructor === String) {
    try {
      config.headers = JSON.parse(config.headers)
    } catch (e) {
      Message.error(`请求头部不是有效的JSON格式:${config.headers}`)
      throw e
    }
  }

  config.headers['Cross-Origin-Embedder-Policy'] = 'require-corp'
  config.headers['Cross-Origin-Opener-Policy'] = 'same-origin'

  config.headers['Accept-Language'] = localStorage.getItem('lang') || 'zh-CN'
  if (store.state.loginAccount) {
    config.headers['Tenant-Code'] = localStorage.getItem(store.state.loginAccount + 'loginRoutePath').replace('/login/', '') || ''
  }
  const currentUser = store.state.currentUser
  currentUser && currentUser.token && !config.headers.Authorization && (config.headers.Authorization = `Bearer ${currentUser.token}`)
  //如果是请求auth接口，则不带token
  if (config.url.indexOf('/auth?') !== -1) {
    delete config.headers.Authorization
  }
  removePending(config) //在一个ajax发送前执行一下取消操作
  config.cancelToken = new cancelToken((c) => {
    // 将请求的地址和请求的方式构建为一个字符串存放到请求数组中
    pending.push({
      u: config.url + '&' + config.method,
      f: c,
      data: config.data
    })
  })

  // 判断是否需要刷新token
  let currentTime = new Date().getTime()
  if (currentUser && currentUser.loginTime && currentTime - currentUser.loginTime >= (currentUser.expiration / 5) * 1000 && config.url.indexOf('/refresh') == -1) {
    $store.dispatch('login/refreshAndGetAuthenticationToken')
  }
  return config
}, error => { // 请求失败的处理
  NProgress.done() // 结束
  return Promise.reject(error)
})


// 响应拦截（配置请求回来的信息）
axios.interceptors.response.use(res => {

  // 是否显示错误信息，默认为显示
  const isShowMessage = res.config.isShowMessage !== undefined ? res.config.isShowMessage : true

  // 取消已完成的请求
  removePending(res.config)

  // 处理错误信息
  if (res.data?.state === false && isShowMessage) {
    Message.errorLog(res.data.message, res.data.logId)
  }

  // 更新加载状态
  store.state.loadding = false

  // 结束进度条
  NProgress.done()

  // 处理附件下载
  if (res.status === 200 && res.headers?.['content-disposition']?.startsWith('attachment;')) {
    const blob = new Blob([res.data])
    const fileName = decodeURIComponent(
      res.headers['content-disposition'].split(';')[1].split('filename=')[1]
    )
    saveAs(blob, fileName)
  }

  return res
}, error => {
  // 判断是否是取消请求导致的错误
  if (axios.isCancel(error)) {
    NProgress.done() // 结束
    return Promise.reject(error)
  }

  // 处理其他类型的错误
  let errorMessage, // 错误响应消息
    bufferErrorResponse // 错误响应体
  if (error?.response?.data instanceof ArrayBuffer) {
    // 使用 TextDecoder 将 ArrayBuffer 转换为字符串
    const decoder = new TextDecoder('utf-8')
    const decodedString = decoder.decode(new Uint8Array(error.response.data))
    try {
      // 解析 JSON 数据
      bufferErrorResponse = JSON.parse(decodedString)
      // 获取错误消息
      errorMessage = bufferErrorResponse.message || error.message || ''
    } catch {
      errorMessage = error.message || ''
    }
  } else {
    bufferErrorResponse = error?.response?.data || {}
    errorMessage = bufferErrorResponse.message || error.message || ''
  }


  if (error?.response?.status === 401) {
    let isJump = JSON.parse(sessionStorage.getItem('isJUmp'))
    sessionStorage.clear()
    if (!['cas', 'oauth'].includes(window.ssoConfig.mode)) {
      //token失效后跳转到门户首页,避免第一次自动跳转
      if (store.state.isLogin) {
        window.location.replace(window.context.defaultLoginUrl)
      } else {
        router.push({path: '/login'})
      }
    }
  } else if (errorMessage) {
    if (bufferErrorResponse.logId) {
      Message.errorLog(errorMessage, bufferErrorResponse.logId)
    } else {
      Message.error(errorMessage)
    }
  }
  NProgress.done() // 结束
  return Promise.reject(errorMessage)
})

Message.errorLog = function(obj, logId) {
  if (typeof obj == 'string' && logId) {
    let msg = obj
    let log = `【日志ID：${logId}】`
    Message({
      type: 'error',
      message: msg + '<div tooltip position=\'right\' class=\'tooltip-wrapper\'><i class=\'icon-question msg-log-icon\'></i><p class=\'msg-log-content\'>' + log + '</p> </div>',
      dangerouslyUseHTMLString: true
    })
  } else {
    Message.error(obj)
  }
}


export default {
  $http: axios,
  request(data) {
    let reqData = data.data || {}
    //支持表达式作为域名解析
    data.url = this.parseUrl(data.url)

    //统一拼接域名接口
    let zsDoorIndex = data.url.indexOf('/zsdoor')
    let zsjIndex = data.url.indexOf('/zsj')
    let base = context.front.slice(0, context.front.indexOf('/fvue'))
    // if(zsjIndex !== -1){
    //     data.url = data.url
    // }else
    if (zsDoorIndex !== -1 || zsjIndex !== -1) {
      data.url = base + data.url
    } else if (data.url.indexOf('/v3/weather/weatherInfo') !== -1) {
      data.url = base + data.url
    } else if (data.url.indexOf('http') == -1 && data.url.indexOf('/v3/weather/weatherInfo') == -1) {
      data.url = context.front + data.url
    }


    if (window.agentLeaderId && window.agentLeaderId != '0' && data.url.indexOf('leaderId=') < 0 &&
      window.location.href.indexOf('/task/') > 1) {
      let mark = '&'
      if (data.url.indexOf('?') < 0) {
        mark = '?'
      }
      data.url += mark + 'leaderId=' + window.agentLeaderId
    }
    let requestData = {
      url: data.url,
      data: reqData,
      method: data.method || 'GET',
      params: data.params || {},
      onUploadProgress: data.onUploadProgress || null,
      headers: data.headers || '',
      responseType: data.responseType || 'json',
      isShowMessage: data.isShowMessage,
      CancelToken: data.CancelToken,
      timeout: data.timeout
    }
    return axios(requestData)
  },
  download(url) {
    return this.request({
      url,
      method: 'POST',
      responseType: 'arraybuffer'
    })
  },
  downloadGet(url) {
    return this.request({
      url,
      method: 'GET',
      responseType: 'arraybuffer'
    })
  },
  downloadPostCopy(url, data) {
    return this.request({
      url,
      method: 'post',
      data: data,
      responseType: 'arraybuffer'
    })
  },
  downloadGetCopy(url, data) {
    return this.request({
      url,
      method: 'get',
      data: data,
      responseType: 'arraybuffer'
    })
  },
  get(url, type, isShowMessage) {
    return this.request({
      url,
      responseType: type,
      isShowMessage: isShowMessage
    })
  },
  post(url, data, responseType, timeout) {
    return this.request({
      url,
      data,
      method: 'POST',
      responseType: responseType,
      timeout
    })
  },
  put(url, data, responseType) {
    return this.request({
      url,
      data,
      method: 'PUT',
      responseType: responseType
    })
  },
  remove(url) {
    return this.request({
      url,
      method: 'DELETE'
    })
  },
  postAduit(url, data, headers) {
    return this.request({
      url,
      data,
      method: 'POST',
      headers: headers
    })
  },
  getDown(url, type, isShowMessage) {
    console.log(url)
    console.log(type)
    return this.request({
      url,
      responseType: type,
      isShowMessage: isShowMessage
    })
  },
  getContext() {
    return context
  },
  parseUrl(url) {
    if (url === '') return
    let ctx = this.getContext(),
      reg = /^(\$\{(\w+)})\/.*$/

    let match = reg.exec(url)
    if (match != null) {
      let name = match[2],
        mc = match[1],
        val = ctx[name]
      if (!val) {
        throw new Error('The \'' + name + '\' in url:' + url + ' does not defined in context provider.')
      }
      return url.replace(mc, val)
    } else {
      return url
    }
  }
}
