import jwtDecode from 'jwt-decode'
import axios from 'axios'
const fefresh_token_api = '/OAUTH_PROXY/token/fresh_token/'
class Token {
  constructor(requestClient) {
    this.moduleName = 'tokenModule'
    this.subscribers = []
    this.isRefreshing = false
    this.requestClient = requestClient
    // 监听消息webframe 发来的消息 设置token 并且刷新队列
    window.addEventListener('message', (e) => {
      if (self === top) return
      if (!e.data) return
      var type = e.data.type
      var data = e.data.data
      if (type === 'setToken') {
        console.log('设置webframe传递过来的token', data)
        // 设置token
        this.setIframeToken(data)
        // 通知本页面的请求重新请求
        this.onAccessTokenFetched(data.token)
        // 解决弹出框里面的iframe过期问题
        this.notifyChildUpdateToken()
      }
    }, false)
  }
  setIframeToken(data) {
    var token = data.token
    sessionStorage['token'] = token
    sessionStorage['refresh_token'] = data.refresh_token
  }
  // 恢复状态
  cleanStatus() {
    this.isRefreshing = false
    this.subscribers = []
  }
  // 刷新token
  async fefreshToken(token = sessionStorage['refresh_token']) {
    const result = await this.requestClient.post(fefresh_token_api, {
      refresh_token: token
    })
    const { access_token, token_type, refresh_token } = result.data
    sessionStorage['refresh_token'] = refresh_token
    sessionStorage['token'] = token_type + ' ' + access_token
    return result
  }
  // 把当前请求推入到数组中存储起来
  addSubscriber(callback) {
    this.subscribers.push(callback)
  }
  // token刷新成功后 把存储起来的请求执行一次
  onAccessTokenFetched(token) {
    this.subscribers.forEach((callback) => {
      callback(token)
    })
    this.cleanStatus()
  }
  // 处理401函数
  hand401Meaage(config) {
    if (!this.isRefreshing) {
      this.isRefreshing = true
      top.postMessage({
        type: 'freshToken'
      }, '*')
    }
    // 这个Promise函数很关键
    const retryOriginalRequest = new Promise((resolve) => {
      this.addSubscriber(() => {
        resolve(axios(config))
      })
    })
    return retryOriginalRequest
  }
  // 处理401函数
  hand401MeaageWebframe(config) {
    if (!this.isRefreshing) {
      // 异步处理 token刷新成功后把缓存的请求全部刷新
      this.fefreshToken().then(res => {
        this.onAccessTokenFetched(res)
      })
    }
    // 这个Promise函数很关键
    const retryOriginalRequest = new Promise((resolve) => {
      this.addSubscriber(() => {
        resolve(axios(config))
      })
    })
    return retryOriginalRequest
  }
  // 判断token是否过期
  checkTokenExpire() {
    const BearerToken = sessionStorage['token']
    if (!BearerToken) return true
    const access_token = BearerToken.slice(7, BearerToken.length)
    const decodeTokenInfo = jwtDecode(access_token)
    const { exp } = decodeTokenInfo
    const now = Math.round(new Date() / 1000)
    return now - exp > 0
  }
  // 判断过期自动刷新
  async checkTokenRefreshToken() {
    const resultCheck = this.checkTokenExpire()
    if (resultCheck) {
      await this.fefreshToken()
    }
  }
  // 更新子iframe
  async updateChildIframeToken() {
    const resultCheck = this.checkTokenExpire()
    if (resultCheck) {
      await this.fefreshToken()
      this.notifyChildUpdateToken()
    }
  }
  notifyChildUpdateToken() {
    const refresh_token = sessionStorage['refresh_token']
    const token = sessionStorage['token']
    const iframes = Array.from(document.getElementsByTagName('iframe'))
    iframes.forEach(item => {
      this.postMessageBycontentWindow(item.contentWindow, {
        type: 'setToken',
        data: {
          refresh_token: refresh_token,
          token: token
        }
      })
    })
  }
  postMessageBycontentWindow(contentWindow, message) {
    contentWindow.postMessage(message, '*')
  }
}
export default Token