import axios from 'axios'
import {Message} from 'element-ui'
import $store from '@/store'
import store from '@/store/login'
import router from '@/router/router.js'
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)) {
        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)

    //统一拼接域名接口

    if (
      data.url.indexOf('http') == -1 &&
      data.url.indexOf('/v3/weather/weatherInfo') == -1
    ) {
      data.url = context.front + data.url
    } else if (data.url.indexOf('/v3/weather/weatherInfo') !== -1) {
      let pureFront = context.front.slice(0, context.front.indexOf('/fvue'))
      data.url = pureFront + 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
    }
  }
}
