import axios from 'axios'
import _ from 'lodash'
import qs from 'qs'

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

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

  /* 获取当前Vue创建实例 */
  getVueInstance() {
    return window.G.$instance_vue
  }

  /* 重新封装 请求时的执行函数 */
  _request(_config = {}) {
    /* 具体执行请求成功后业务逻辑前，先执行该方法 */
    const beforeSuccess = _config.beforeSuccess ? _config.beforeSuccess : this._reqSuccess
    /* 具体执行请求失败后业务逻辑前，先执行该方法 */
    const beforeFail = _config.beforeFail ? _config.beforeFail : this._reqFail
    const headers = {
      tenant: 'sofia',
      version: window.G.VERSION,
      'Content-Type': 'application/x-www-form-urlencoded'
    }
    _config.headers = _.assignIn(headers, _config.headers)
    /* 判别 传输方式 */
    if (_config.headers['Content-Type'] === 'application/x-www-form-urlencoded') {
      _config.data = qs.stringify(_config.data)
    }
    if (_config.headers['Content-Type'] === 'multipart/form-data') {
      let fr = new FormData() // eslint-disable-line
      const _obj = _config.data || _config.params
      for (const key in _obj) {
        fr.append(key, _obj[key])
      }
      _config.data = fr
    }
    /* 创建并根据参数发起请求 */
    return this._axios(_config).then(beforeSuccess.bind(this), beforeFail.bind(this))
  }

  setConfirm(titleStr, btnStr, msgStr) {
    return MessageBox.confirm(msgStr, titleStr, {
      confirmButtonText: btnStr,
      type: 'warning',
      showClose: false,
      closeOnPressEscape: false,
      closeOnClickModal: false,
      showCancelButton: false
    })
  }

  goLoginIndex(_vIn) {
    const href = window.location.href
    if (/\/login\/index/gi.test(href)) {
      _vIn.$router.go(0)
    } else {
      // _vIn.$router.push({
      //   path: '/login/index?rd=' + encodeURIComponent(href.replace(/.*?\/\/.*?\//gi, '/'))
      // })
      window.location.href = `${webConf.others.loginUrl}?rd=${encodeURIComponent(window.location.href)}`
    }
  }

  /**
   * 统一处理request success操作，在实现业务逻辑前进行统一处理。
   * 注意：如果不能满足需求，可在接口定义处重新实现
   * @param {[object]} res 返回数据
   */
  _reqSuccess(res) {
    const { data } = res
    /* 带 code 参数，新接口模型 */
    if (data.code !== undefined) {
      if (data.code !== 0 && !/getinfo$/gi.test(res.config.url)) {
        data.msg && Message({ type: 'error', message: data.msg })
      }
    }
    return data
  }

  /**
   * 统一处理request fail操作，在实现业务逻辑前进行统一处理。
   * 注意：如果不能满足需求，可在接口定义处重新实现
   * @param {[object]} res 如果未到达 response 阶段，则无res.response
   */
  _reqFail(res) {
    const _vIn = this.getVueInstance()
    let err = null
    if (res.code === 'ECONNABORTED') {
      err = new Error('网络超时，请稍后重试')
    } else if (res.response) {
      const { status, data } = res.response
      /* 不带 code 参数，老接口模型 */
      if (data) {
        if (status === 403 && !/getinfo$/gi.test(res.config.url)) {
          this.setConfirm('提示', '确定', '登录状态已过期, 请重新登录。')
            .then(() => {
              this.goLoginIndex(_vIn)
            })
            .catch(() => {
              Message({
                type: 'info',
                message: '已取消，将不再记录任何数据操作，除非重新登录'
              })
            })
        } else if (status === 401) {
          _vIn.$router.push({ path: '/403' })
        }
      }
      err = new Error(data.message || JSON.stringify(data))
      err.code = data.code
      err.status = data.status
    } 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))
  }
}
