import merge from 'element-ui/src/utils/merge'
import { isVNode } from 'element-ui/src/utils/vdom'
import { isObject } from 'element-ui/src/utils/types'

export default function install(Vue) {
  const originMsgbox = Vue.prototype.$msgbox
  Vue.prototype.$msgbox = function(message, title, type) {
    let options
    if (typeof message === 'object') {
      options = message
    } else {
      options = {
        message,
        title,
        type
      }
    }
    const h = this.$createElement
    return originMsgbox({
      beforeClose: typeof options.confirmHandlerPromise === 'function' ? (action, instance, done) => {
        if (action === 'confirm') {
          instance.confirmButtonLoading = true
          try {
            const promise = options.confirmHandlerPromise(instance)
            if (promise instanceof Promise) {
              promise.then(() => {
                done()
              }).finally(() => {
                instance.confirmButtonLoading = false
              })
            } else {
              console.warn(`confirmHandlerPromise is not a promise`)
            }
          } catch (e) {
            instance.confirmButtonLoading = false
            console.error(e)
          }
        } else if (!instance.confirmButtonLoading) {
          done()
        }
      } : undefined,
      ...options,
      message: typeof options.message === 'string' ? h('div', null, options.message.split('\n').map((item) => {
        return h('p', null, item)
      })) : options.message
    })
  }

  Vue.prototype.$confirm = function(message, title, options) {
    if (typeof title === 'object') {
      options = title
      title = ''
    } else if (title === undefined) {
      title = ''
    }
    return this.$msgbox(merge({
      title: title,
      message: message,
      $type: 'confirm',
      showCancelButton: true
    }, options))
  }

  const originMessage = Vue.prototype.$message
  const messageOptionList = []
  let messageLock = false
  const nextMessage = function() {
    if (messageLock || messageOptionList.length === 0) {
      return
    }
    messageLock = true
    const option = messageOptionList.pop()
    option.resolve(originMessage(option))
    setTimeout(() => {
      messageLock = false
      nextMessage()
    }, 100)
  }
  Vue.prototype.$message = function(options) {
    return new Promise((resolve) => {
      messageOptionList.push({
        ...options,
        resolve
      })
      nextMessage()
    })
  }
  for (const originMessageKey of ['success', 'warning', 'info', 'error']) {
    Vue.prototype.$message[originMessageKey] = (options) => {
      if (isObject(options) && !isVNode(options)) {
        return Vue.prototype.$message({
          ...options,
          type: originMessageKey
        })
      }
      return Vue.prototype.$message({
        type: originMessageKey,
        message: options
      })
    }
  }
}
