import axios from 'axios'
import _ from 'lodash'
import Base64 from 'Base64'
// import tools from '@tools'

import { MessageBox, Message } from 'element-ui'

export default class API {
  constructor (config) {
    /* 创建一个 自定义配置axios实例 */
    axios.defaults.withCredentials = true // 让ajax携带cookie
    this._axios = axios.create({
      timeout: config.timeout || 5 * 1000,
      /* 表示服务器响应的数据类型，可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream' */
      responseType: config.resType || 'json',
      /* 将自动加在 `url` 前面，除非 `url` 是一个绝对 URL */
      baseURL: config.apiBaseURL || '',
      /* 即将被发送的自定义请求头 */
      headers: {
        'Accept': '*/*',
        'Accept-Language': '',
        'Content-Type': 'application/json'
      }
    })
  }

  /* 重新封装 请求时的执行函数 */
  _request (_config = {}) {
    /* 具体执行请求成功后业务逻辑前，先执行该方法 */
    let beforeSuccess = _config.beforeSuccess ? _config.beforeSuccess : this._reqSuccess
    /* 具体执行请求失败后业务逻辑前，先执行该方法 */
    let beforeFail = _config.beforeFail ? _config.beforeFail : this._reqFail
    /* 这里可以统一处理 登录 */

    /**
     * 增加 Cookie 和 请求头传值，如果是 服务端渲染，就放Node端
     * 所有请求 全部增加 token 和 tenant 请求头并 自带 cookie
     */
    // let s = decodeURIComponent(tools.cookies.getCookie('_SUP') || '')
    // let ticket = ''
    // s = s.match(/"([\d\w=]+)";\}$/)
    // if (s && s.length === 2) {
    //   s = new Buffer(s[1], 'base64').toString() // eslint-disable-line
    //   s = s.slice(12, s.search('-TGT') + 4)
    //   ticket = s.split('').reverse().join('')
    // }
    let _uInfo = window.G.UserInfo || {}
    let headers = {
      // 'X-Forwarded-For': req.get('x-forwarded-for'),
      // 'X-Real-Ip': req.get('x-real-ip'),
      'cur-json': Base64.encode(JSON.stringify({
        time: new Date().getTime(),
        sys: 'elearning-node',
        auth: _uInfo.email || _uInfo.mobile || '未知', // 在header头中传入 当前用户账号信息
        name: (_uInfo.student_info && _uInfo.student_info.personal_name) || _uInfo.username || '未知', // 在header头中传入 当前用户姓名
        version: window.G.VERSION // 版本号 修改
      })),
      // 'token': ticket,
      'tenant': 'sofia',
      'version': window.G.VERSION
    }
    if (/user\/login/gi.test(_config.url)) {
      headers.pmd5 = _config.data.pwd
      delete _config.data.pwd
    }
    _config.headers = _.assignIn(_config.headers, headers)
    /* 判别传输方式 */
    if (_config.headers['Content-Type'] === 'application/x-www-form-urlencoded') {
      /* 必须使用 Form-Data 方式 */
      let str = ''
      let _obj = _config.data || _config.params
      for (let key in _obj) {
        str += key + '=' + _obj[key] + '&'
      }
      str = str.substr(0, str.length - 1)
      if (_config.data) {
        _config.data = str
      } else {
        _config.params = str
      }
    }
    if (_config.headers['Content-Type'] === 'multipart/form-data') {
      let fr = new FormData() // eslint-disable-line
      let _obj = _config.data || _config.params
      for (let key in _obj) {
        fr.append(key, _obj[key])
      }
      _config.data = fr
    }
    /* 创建并根据参数发起请求 */
    return this._axios(_config)
      .then(beforeSuccess.bind(this), beforeFail.bind(this))
  }

  /**
   * 统一处理request success操作，在实现业务逻辑前进行统一处理。
   * 注意：如果不能满足需求，可在接口定义处重新实现
   * @param {[object]} res 返回数据
   */
  _reqSuccess (res) {
    let { status, data } = res
    let err = null
    /* 针对 MBA学习系统 做特殊 请求成功处理 */
    if (status === 200) {
      if (data.status === 403 && !/\/getinfo$/gi.test(res.config.url)) {
        MessageBox.confirm('登录状态已过期, 请重新登录。', '提示', {
          confirmButtonText: '确定',
          // cancelButtonText: '取消',
          type: 'warning',
          showClose: false,
          closeOnPressEscape: false,
          closeOnClickModal: false,
          showCancelButton: false
        }).then(() => {
          /* 重新刷新当前页 */
          window.location.reload()
        }).catch(() => {
          Message({
            type: 'info',
            message: '已取消，将不再记录任何数据操作，除非重新登录'
          })
        })
      } else if (data.status !== 200 && data.message && !data.code && !data.success) {
        err = new Error(data.message)
        throw err
      } else {
        return data
      }
    } else {
      err = new Error(JSON.stringify(res.data))
      throw err
    }
  }

  /**
   * 统一处理request fail操作，在实现业务逻辑前进行统一处理。
   * 注意：如果不能满足需求，可在接口定义处重新实现
   * @param {[object]} res 如果未到达 response 阶段，则无res.response
   */
  _reqFail (res) {
    let err = null
    if (res.response) {
      if (res.response.data) {
        if (!/\/getinfo$/gi.test(res.config.url) && res.response.data.status === 403) {
          MessageBox.confirm('登录状态已过期, 请重新登录。', '提示', {
            confirmButtonText: '确定',
            // cancelButtonText: '取消',
            type: 'warning',
            showClose: false,
            closeOnPressEscape: false,
            closeOnClickModal: false,
            showCancelButton: false
          }).then(() => {
            /* 重新刷新当前页 */
            window.location.reload()
          }).catch(() => {
            this.$message({
              type: 'info',
              message: '已取消，将不再记录任何数据操作，除非重新登录'
            })
          })
        }
        err = new Error(res.response.data.message)
      } else if (res.response.data.status === 401 && res.response.data.message) {
        MessageBox.confirm(res.response.data.message, '提示', {
          confirmButtonText: '关闭',
          // cancelButtonText: '取消',
          type: 'warning',
          showClose: false,
          closeOnPressEscape: false,
          closeOnClickModal: false,
          showCancelButton: false
        }).then(() => {
          /* 重新刷新当前页 */
          window.location.reload()
        })
      } else {
        /* 错误处理，服务端非正常返回 */
        err = new Error(JSON.stringify(res.response))
      }
    } else if (res.code === 'ECONNABORTED') {
      err = new Error('网络超时，请稍后重试')
    } else {
      err = new Error('msg:' + res.message + 'stack:' + res.stack)
      err.code = 500
    }
    /* 如果出错，创建错误对象，并抛出一个错误。 */
    throw err
  }

  /* 重新实现 get请求 */
  get (url, data, config) { return this._request(_.assignIn({ url, method: 'GET', params: data }, config)) }
  /* 重新实现 post请求 */
  post (url, data, config) { return this._request(_.assignIn({ url, method: 'POST', data: data }, config)) }
  /* 重新实现 put请求 */
  put (url, data, config) { return this._request(_.assignIn({ url, method: 'PUT', data: data }, config)) }
  /* 重新实现 delete请求 */
  delete (url, data, config) { return this._request(_.assignIn({ url, method: 'DELETE', params: data }, config)) }
}
