import { h, ref, computed, Teleport, resolveComponent, VNode, onUnmounted, reactive, nextTick, PropType, onMounted, inject } from 'vue'
import { defineVxeComponent } from '../../ui/src/comp'
import XEUtils from 'xe-utils'
import { getConfig, globalEvents, getIcon, createEvent, useSize, renderer, usePermission, permission, renderEmptyElement } from '../../ui'
import { getEventTargetNode, updatePanelPlacement } from '../../ui/src/dom'
import { getFuncText, getLastZIndex, nextZIndex } from '../../ui/src/utils'
import { getSlotVNs } from '../../ui/src/vn'
import { warnLog } from '../../ui/src/log'
import VxeTooltipComponent from '../../tooltip'

import type { VxeButtonConstructor, VxeButtonPropTypes, VxeButtonEmits, ButtonReactData, ButtonMethods, VxeButtonDefines, ButtonPrivateRef, ButtonInternalData, VxeButtonGroupConstructor, VxeButtonGroupPrivateMethods, VxeDrawerConstructor, VxeDrawerMethods, VxeFormConstructor, VxeFormPrivateMethods, VxeModalConstructor, VxeModalMethods, ValueOf, VxeTreeConstructor, VxeTreePrivateMethods } from '../../../types'
import type { VxeTableConstructor, VxeTablePrivateMethods } from '../../../types/components/table'

const VxeButtonComponent = defineVxeComponent({
  name: 'VxeButton',
  props: {
    /**
     * 按钮类型
     */
    type: String as PropType<VxeButtonPropTypes.Type>,
    mode: String as PropType<VxeButtonPropTypes.Mode>,
    className: [String, Function] as PropType<VxeButtonPropTypes.ClassName>,
    popupClassName: [String, Function] as PropType<VxeButtonPropTypes.PopupClassName>,
    /**
     * 按钮尺寸
     */
    size: {
      type: String as PropType<VxeButtonPropTypes.Size>,
      default: () => getConfig().button.size || getConfig().size
    },
    zIndex: Number as PropType<VxeButtonPropTypes.ZIndex>,
    /**
     * 用来标识这一项
     */
    name: [String, Number] as PropType<VxeButtonPropTypes.Name>,
    routerLink: Object as PropType<VxeButtonPropTypes.RouterLink>,
    /**
     * 权限码
     */
    permissionCode: [String, Number] as PropType<VxeButtonPropTypes.PermissionCode>,
    /**
     * 按钮内容
     */
    content: String as PropType<VxeButtonPropTypes.Content>,
    /**
     * 固定显示下拉面板的方向
     */
    placement: String as PropType<VxeButtonPropTypes.Placement>,
    /**
     * 按钮状态
     */
    status: String as PropType<VxeButtonPropTypes.Status>,
    /**
     * 标题
     */
    title: String as PropType<VxeButtonPropTypes.Title>,
    shadow: Boolean as PropType<VxeButtonPropTypes.Shadow>,
    /**
     * 按钮的前缀图标，属于 prefix-icon 的简写
     */
    icon: String as PropType<VxeButtonPropTypes.Icon>,
    iconRender: Object as PropType<VxeButtonPropTypes.IconRender>,
    /**
     * 按钮的前缀图标
     */
    prefixIcon: String as PropType<VxeButtonPropTypes.PrefixIcon>,
    prefixRender: Object as PropType<VxeButtonPropTypes.PrefixRender>,
    /**
     * 按钮的后缀图标
     */
    suffixIcon: String as PropType<VxeButtonPropTypes.SuffixIcon>,
    suffixRender: Object as PropType<VxeButtonPropTypes.SuffixRender>,
    /**
     * 圆角边框
     */
    round: Boolean as PropType<VxeButtonPropTypes.Round>,
    /**
     * 圆角按钮
     */
    circle: Boolean as PropType<VxeButtonPropTypes.Circle>,
    /**
     * 是否禁用
     */
    disabled: Boolean as PropType<VxeButtonPropTypes.Disabled>,
    /**
     * 是否加载中
     */
    loading: Boolean as PropType<VxeButtonPropTypes.Loading>,
    trigger: {
      type: String as PropType<VxeButtonPropTypes.Trigger>,
      default: () => getConfig().button.trigger
    },
    align: String as PropType<VxeButtonPropTypes.Align>,
    prefixTooltip: Object as PropType<VxeButtonPropTypes.PrefixTooltip>,
    suffixTooltip: Object as PropType<VxeButtonPropTypes.SuffixTooltip>,
    options: Array as PropType<VxeButtonPropTypes.Options>,
    showDropdownIcon: {
      type: Boolean,
      default: () => getConfig().button.showDropdownIcon
    },
    /**
     * 在下拉面板关闭时销毁内容
     */
    destroyOnClose: {
      type: Boolean as PropType<VxeButtonPropTypes.DestroyOnClose>,
      default: () => getConfig().button.destroyOnClose
    },
    popupConfig: Object as PropType<VxeButtonPropTypes.PopupConfig>,
    /**
     * 是否将弹框容器插入于 body 内
     */
    transfer: {
      type: Boolean as PropType<VxeButtonPropTypes.Transfer>,
      default: null
    }
  },
  emits: [
    'click',
    'mouseenter',
    'mouseleave',
    'dropdown-click',
    'dropdownClick',
    'contextmenu'
  ] as VxeButtonEmits,
  setup (props, context) {
    const { slots, emit } = context

    const $xeModal = inject<(VxeModalConstructor & VxeModalMethods)| null>('$xeModal', null)
    const $xeDrawer = inject<(VxeDrawerConstructor & VxeDrawerMethods) | null>('$xeDrawer', null)
    const $xeTable = inject<(VxeTableConstructor & VxeTablePrivateMethods) | null>('$xeTable', null)
    const $xeTree = inject<(VxeTreeConstructor & VxeTreePrivateMethods) | null>('$xeTree', null)
    const $xeForm = inject<(VxeFormConstructor & VxeFormPrivateMethods)| null>('$xeForm', null)
    const $xeButtonGroup = inject<(VxeButtonGroupConstructor & VxeButtonGroupPrivateMethods) | null>('$xeButtonGroup', null)

    const xID = XEUtils.uniqueId()

    const { computeSize } = useSize(props)

    const { computePermissionInfo } = usePermission(props)

    const reactData = reactive<ButtonReactData>({
      initialized: false,
      visiblePanel: false,
      isAniVisible: false,
      isActivated: false,
      panelIndex: 0,
      panelStyle: {},
      panelPlacement: ''
    })

    const internalData: ButtonInternalData = {
      showTime: undefined,
      tooltipTimeout: undefined
    }

    const refElem = ref<HTMLDivElement>()
    const refButton = ref<HTMLButtonElement>()
    const refBtnPanel = ref<HTMLDivElement>()

    const refMaps: ButtonPrivateRef = {
      refElem
    }

    const $xeButton = {
      xID,
      props,
      context,
      reactData,
      internalData,
      getRefMaps: () => refMaps
    } as unknown as VxeButtonConstructor

    let buttonMethods = {} as ButtonMethods

    const computeBtnTransfer = computed(() => {
      const { transfer } = props
      const popupOpts = computePopupOpts.value
      if (XEUtils.isBoolean(popupOpts.transfer)) {
        return popupOpts.transfer
      }
      if (transfer === null) {
        const globalTransfer = getConfig().button.transfer
        if (XEUtils.isBoolean(globalTransfer)) {
          return globalTransfer
        }
        if ($xeTable || $xeTree || $xeModal || $xeDrawer || $xeForm) {
          return true
        }
      }
      return transfer
    })

    const computeBtnDisabled = computed(() => {
      const { disabled } = props
      const permissionInfo = computePermissionInfo.value
      return disabled || permissionInfo.disabled
    })

    const computeIsFormBtn = computed(() => {
      const { type } = props
      if (type) {
        return ['submit', 'reset', 'button'].indexOf(type) > -1
      }
      return false
    })

    const computeBtnMode = computed(() => {
      const { type, mode } = props
      if (mode === 'text' || type === 'text' || ($xeButtonGroup && $xeButtonGroup.props.mode === 'text')) {
        return 'text'
      }
      return 'button'
    })

    const computeBtnStatus = computed(() => {
      const { status } = props
      if (status) {
        return status
      }
      if ($xeButtonGroup) {
        return $xeButtonGroup.props.status
      }
      return ''
    })

    const computeBtnAlign = computed(() => {
      const { align } = props
      if (align) {
        return align
      }
      if ($xeButtonGroup) {
        return $xeButtonGroup.props.align
      }
      return false
    })

    const computeBtnRound = computed(() => {
      const { round } = props
      if (round) {
        return round
      }
      if ($xeButtonGroup) {
        return $xeButtonGroup.props.round
      }
      return false
    })

    const computeBtnCircle = computed(() => {
      const { circle } = props
      if (circle) {
        return circle
      }
      if ($xeButtonGroup) {
        return $xeButtonGroup.props.circle
      }
      return false
    })

    const computeDownBtnList = computed(() => {
      const { options } = props
      if (options) {
        return options.filter(item => {
          const { permissionCode } = item
          return !permissionCode || permission.checkVisible(permissionCode)
        })
      }
      return []
    })

    const computePopupOpts = computed(() => {
      return Object.assign({}, getConfig().button.popupConfig, props.popupConfig)
    })

    const computePrefixTipOpts = computed(() => {
      return Object.assign({}, getConfig().button.prefixTooltip, props.prefixTooltip)
    })

    const computeSuffixTipOpts = computed(() => {
      return Object.assign({}, getConfig().button.suffixTooltip, props.suffixTooltip)
    })

    const updateZindex = () => {
      const popupOpts = computePopupOpts.value
      const customZIndex = popupOpts.zIndex || props.zIndex
      if (customZIndex) {
        reactData.panelIndex = XEUtils.toNumber(customZIndex)
      } else if (reactData.panelIndex < getLastZIndex()) {
        reactData.panelIndex = nextZIndex()
      }
    }

    const updatePlacement = () => {
      const { placement } = props
      const { panelIndex } = reactData
      const targetElem = refButton.value
      const panelElem = refBtnPanel.value
      const btnTransfer = computeBtnTransfer.value
      const popupOpts = computePopupOpts.value
      const handleStyle = () => {
        const ppObj = updatePanelPlacement(targetElem, panelElem, {
          placement: popupOpts.placement || placement,
          defaultPlacement: (popupOpts as any).defaultPlacement,
          teleportTo: btnTransfer
        })
        const panelStyle: { [key: string]: string | number } = Object.assign(ppObj.style, {
          zIndex: panelIndex
        })
        reactData.panelStyle = panelStyle
        reactData.panelPlacement = ppObj.placement
      }
      handleStyle()
      return nextTick().then(handleStyle)
    }

    const clickEvent = (evnt: Event) => {
      if ($xeButtonGroup) {
        $xeButtonGroup.handleClick({ name: props.name }, evnt)
      }
      dispatchEvent('click', { $event: evnt }, evnt)
    }

    const downBtnClickEvent = (params: VxeButtonDefines.ClickEventParams, option: VxeButtonDefines.DownButtonOption) => {
      const { $event } = params
      hidePanel()
      dispatchEvent('dropdown-click', { name: option.name, option }, $event)
    }

    const mousedownDropdownEvent = (evnt: MouseEvent) => {
      const isLeftBtn = evnt.button === 0
      if (isLeftBtn) {
        evnt.stopPropagation()
      }
    }

    const clickDropdownEvent = (evnt: Event) => {
      const dropdownElem = evnt.currentTarget
      const panelElem = refBtnPanel.value
      const { flag, targetElem } = getEventTargetNode(evnt, dropdownElem, 'vxe-button')
      if (flag) {
        if (panelElem) {
          panelElem.dataset.active = 'N'
        }
        reactData.visiblePanel = false
        setTimeout(() => {
          if (!panelElem || panelElem.dataset.active !== 'Y') {
            reactData.isAniVisible = false
          }
        }, 350)
        dispatchEvent('dropdown-click', { name: targetElem.getAttribute('name'), option: null }, evnt)
      }
    }

    const mouseenterDropdownEvent = () => {
      const panelElem = refBtnPanel.value
      if (panelElem) {
        panelElem.dataset.active = 'Y'
        reactData.isAniVisible = true
        setTimeout(() => {
          if (panelElem.dataset.active === 'Y') {
            reactData.visiblePanel = true
            updateZindex()
            updatePlacement()
            setTimeout(() => {
              if (reactData.visiblePanel) {
                updatePlacement()
              }
            }, 50)
          }
        }, 20)
      }
    }

    const mouseenterTargetEvent = (evnt: MouseEvent) => {
      const { loading } = props
      const btnDisabled = computeBtnDisabled.value
      if (!(btnDisabled || loading)) {
        openPanel()
        mouseenterEvent(evnt)
      }
    }

    const mouseleaveTargetEvent = (evnt: MouseEvent) => {
      hidePanel()
      mouseleaveEvent(evnt)
    }

    const mouseenterEvent = (evnt: MouseEvent) => {
      dispatchEvent('mouseenter', {}, evnt)
    }

    const mouseleaveEvent = (evnt: MouseEvent) => {
      dispatchEvent('mouseleave', {}, evnt)
    }

    const contextmenuEvent = (evnt: MouseEvent) => {
      dispatchEvent('contextmenu', {}, evnt)
    }

    const clickTargetEvent = (evnt: MouseEvent) => {
      const { loading, trigger } = props
      const btnDisabled = computeBtnDisabled.value
      if (!(btnDisabled || loading)) {
        if (trigger === 'click') {
          if (reactData.visiblePanel) {
            hidePanel()
          } else {
            openPanel()
          }
        }
        clickEvent(evnt)
      }
    }

    const openPanel = () => {
      const { trigger } = props
      const panelElem = refBtnPanel.value
      if (panelElem) {
        panelElem.dataset.active = 'Y'
        if (!reactData.initialized) {
          reactData.initialized = true
        }
        internalData.showTime = setTimeout(() => {
          if (panelElem.dataset.active === 'Y') {
            mouseenterDropdownEvent()
          } else {
            reactData.isAniVisible = false
          }
        }, trigger === 'click' ? 50 : 250)
      }
      return nextTick()
    }

    const hidePanel = () => {
      const panelElem = refBtnPanel.value
      clearTimeout(internalData.showTime)
      if (panelElem) {
        panelElem.dataset.active = 'N'
        setTimeout(() => {
          if (panelElem.dataset.active !== 'Y') {
            reactData.visiblePanel = false
            setTimeout(() => {
              if (panelElem.dataset.active !== 'Y') {
                reactData.isAniVisible = false
              }
            }, 350)
          }
        }, 100)
      } else {
        reactData.isAniVisible = false
        reactData.visiblePanel = false
      }
      return nextTick()
    }

    const mouseleaveDropdownEvent = () => {
      hidePanel()
    }

    const renderTooltipIcon = (tipOpts: VxeButtonPropTypes.PrefixTooltip | VxeButtonPropTypes.SuffixTooltip, type: 'prefix' | 'suffix') => {
      return h(VxeTooltipComponent, {
        useHTML: tipOpts.useHTML,
        content: tipOpts.content,
        enterable: tipOpts.enterable,
        theme: tipOpts.theme
      }, {
        default () {
          return h('span', {
            class: `vxe-button--item vxe-button--tooltip-${type}-icon`
          }, [
            h('i', {
              class: tipOpts.icon || getIcon().BUTTON_TOOLTIP_ICON
            })
          ])
        }
      })
    }

    const renderContent = () => {
      const { content, suffixIcon, loading, prefixTooltip, suffixTooltip, suffixRender } = props
      const prefixIcon = props.prefixIcon || props.icon
      const prefixRender = props.prefixRender || props.iconRender
      const prefixTipOpts = computePrefixTipOpts.value
      const suffixTipOpts = computeSuffixTipOpts.value
      const prefixIconSlot = slots.prefix || slots.icon
      const suffixIconSlot = slots.suffix
      const defaultSlot = slots.default
      const contVNs: VNode[] = []
      if (prefixTooltip) {
        contVNs.push(
          renderTooltipIcon(prefixTipOpts, 'prefix')
        )
      }
      if (loading) {
        contVNs.push(
          h('i', {
            class: ['vxe-button--item vxe-button--loading-icon', getIcon().BUTTON_LOADING]
          })
        )
      } else if (prefixIconSlot) {
        contVNs.push(
          h('span', {
            class: 'vxe-button--item vxe-button--custom-prefix-icon'
          }, prefixIconSlot({}))
        )
      } else if (prefixRender) {
        const compConf = renderer.get(prefixRender.name)
        const pIconMethod = compConf ? compConf.renderButtonPrefix : null
        contVNs.push(
          h('span', {
            class: ['vxe-button--item vxe-button--custom-prefix-icon']
          }, pIconMethod ? getSlotVNs(pIconMethod(prefixRender, { $button: $xeButton })) : [])
        )
      } else if (prefixIcon) {
        contVNs.push(
          h('i', {
            class: ['vxe-button--item vxe-button--prefix-icon', prefixIcon]
          })
        )
      }

      if (defaultSlot) {
        contVNs.push(
          h('span', {
            class: 'vxe-button--item vxe-button--content'
          }, defaultSlot({}))
        )
      } else if (content) {
        contVNs.push(
          h('span', {
            class: 'vxe-button--item vxe-button--content'
          }, getFuncText(content))
        )
      }

      if (suffixIconSlot) {
        contVNs.push(
          h('span', {
            class: 'vxe-button--item vxe-button--custom-suffix-icon'
          }, suffixIconSlot({}))
        )
      } else if (suffixRender) {
        const compConf = renderer.get(suffixRender.name)
        const sIconMethod = compConf ? compConf.renderButtonSuffix : null
        contVNs.push(
          h('span', {
            class: ['vxe-button--item vxe-button--custom-suffix-icon']
          }, sIconMethod ? getSlotVNs(sIconMethod(suffixRender, { $button: $xeButton })) : [])
        )
      } else if (suffixIcon) {
        contVNs.push(
          h('i', {
            class: ['vxe-button--item vxe-button--suffix-icon', suffixIcon]
          })
        )
      }
      if (suffixTooltip) {
        contVNs.push(
          renderTooltipIcon(suffixTipOpts, 'suffix')
        )
      }
      return contVNs
    }

    const dispatchEvent = (type: ValueOf<VxeButtonEmits>, params: Record<string, any>, evnt: Event | null) => {
      emit(type, createEvent(evnt, { $button: $xeButton }, params))
    }

    buttonMethods = {
      dispatchEvent,
      openPanel,
      closePanel: hidePanel,
      focus () {
        const btnElem = refButton.value
        if (btnElem) {
          btnElem.focus()
        }
        return nextTick()
      },
      blur () {
        const btnElem = refButton.value
        if (btnElem) {
          btnElem.blur()
        }
        return nextTick()
      }
    }

    const handleGlobalMousewheelEvent = (evnt: Event) => {
      const panelElem = refBtnPanel.value
      if (reactData.visiblePanel && !getEventTargetNode(evnt, panelElem).flag) {
        hidePanel()
      }
    }

    const handleGlobalMousedownEvent = (evnt: MouseEvent) => {
      const btnDisabled = computeBtnDisabled.value
      const { visiblePanel } = reactData
      if (!btnDisabled) {
        const el = refElem.value
        const panelElem = refBtnPanel.value
        reactData.isActivated = getEventTargetNode(evnt, el).flag || getEventTargetNode(evnt, panelElem).flag
        if (visiblePanel && !reactData.isActivated) {
          hidePanel()
        }
      }
    }

    const handleGlobalResizeEvent = () => {
      const { visiblePanel } = reactData
      if (visiblePanel) {
        updatePlacement()
      }
    }

    Object.assign($xeButton, buttonMethods)

    const renderVN = () => {
      const { className, trigger, title, routerLink, type, destroyOnClose, name, loading, shadow, showDropdownIcon } = props
      const { initialized, isAniVisible, visiblePanel } = reactData
      const isFormBtn = computeIsFormBtn.value
      const btnMode = computeBtnMode.value
      const btnStatus = computeBtnStatus.value
      const btnRound = computeBtnRound.value
      const btnAlign = computeBtnAlign.value
      const btnCircle = computeBtnCircle.value
      const btnTransfer = computeBtnTransfer.value
      const btnDisabled = computeBtnDisabled.value
      const permissionInfo = computePermissionInfo.value
      const downBtnList = computeDownBtnList.value
      const popupOpts = computePopupOpts.value
      const vSize = computeSize.value
      const dropdownsSlot = slots.dropdowns
      const ppClassName = popupOpts.className || props.popupClassName

      if (!permissionInfo.visible) {
        return renderEmptyElement($xeButton)
      }
      if (dropdownsSlot || downBtnList.length) {
        const btnOns: Record<string, any> = {
          onContextmenu: contextmenuEvent
        }
        const panelOns: Record<string, any> = {}
        if (trigger === 'hover') {
          // hover 触发
          btnOns.onMouseenter = mouseenterTargetEvent
          btnOns.onMouseleave = mouseleaveTargetEvent

          panelOns.onMouseenter = mouseenterDropdownEvent
          panelOns.onMouseleave = mouseleaveDropdownEvent
        }
        return h('div', {
          ref: refElem,
          class: ['vxe-button--dropdown', className ? (XEUtils.isFunction(className) ? className({ $button: $xeButton }) : className) : '', {
            [`size--${vSize}`]: vSize,
            'is--active': visiblePanel
          }]
        }, [
          routerLink
            ? h(resolveComponent('router-link'), {
              ref: refButton,
              class: ['vxe-button', 'vxe-button--link', `type--${btnMode}`, btnAlign ? `align--${btnAlign}` : '', className ? (XEUtils.isFunction(className) ? className({ $button: $xeButton }) : className) : '', {
                [`size--${vSize}`]: vSize,
                [`theme--${btnStatus}`]: btnStatus,
                'is--round': btnRound,
                'is--circle': btnCircle,
                'is--shadow': shadow,
                'is--disabled': btnDisabled || loading,
                'is--loading': loading
              }],
              title,
              name,
              type: isFormBtn ? type : 'button',
              disabled: btnDisabled || loading,
              to: routerLink,
              onClick: clickTargetEvent,
              ...btnOns
            }, {
              default () {
                return renderContent().concat(showDropdownIcon
                  ? [
                      h('i', {
                        class: `vxe-button--dropdown-arrow ${getIcon().BUTTON_DROPDOWN}`
                      })
                    ]
                  : [])
              }
            })
            : h('button', {
              ref: refButton,
              class: ['vxe-button', `type--${btnMode}`, btnAlign ? `align--${btnAlign}` : '', className ? (XEUtils.isFunction(className) ? className({ $button: $xeButton }) : className) : '', {
                [`size--${vSize}`]: vSize,
                [`theme--${btnStatus}`]: btnStatus,
                'is--round': btnRound,
                'is--circle': btnCircle,
                'is--shadow': shadow,
                'is--disabled': btnDisabled || loading,
                'is--loading': loading
              }],
              title,
              name,
              type: isFormBtn ? type : 'button',
              disabled: btnDisabled || loading,
              onClick: clickTargetEvent,
              ...btnOns
            }, renderContent().concat(showDropdownIcon
              ? [
                  h('i', {
                    class: `vxe-button--dropdown-arrow ${getIcon().BUTTON_DROPDOWN}`
                  })
                ]
              : [])),
          h(Teleport, {
            to: 'body',
            disabled: btnTransfer ? !initialized : true
          }, [
            h('div', {
              ref: refBtnPanel,
              class: ['vxe-button--dropdown-panel', ppClassName ? (XEUtils.isFunction(ppClassName) ? ppClassName({ $button: $xeButton }) : ppClassName) : '', {
                [`size--${vSize}`]: vSize,
                'is--transfer': btnTransfer,
                'ani--leave': isAniVisible,
                'ani--enter': visiblePanel
              }],
              placement: reactData.panelPlacement,
              style: reactData.panelStyle,
              ...panelOns
            }, initialized && (visiblePanel || isAniVisible)
              ? [
                  dropdownsSlot
                    ? h('div', {
                      class: 'vxe-button--dropdown-wrapper',
                      onMousedown: mousedownDropdownEvent,
                      onClick: clickDropdownEvent
                    }, initialized && (destroyOnClose ? (visiblePanel || isAniVisible) : true) ? dropdownsSlot({}) : [])
                    : h('div', {
                      class: 'vxe-button--dropdown-wrapper'
                    }, initialized && (destroyOnClose ? (visiblePanel || isAniVisible) : true)
                      ? downBtnList.map((option, i) => {
                        return h(VxeButtonComponent, {
                          key: i,
                          type: option.type,
                          mode: option.mode || btnMode,
                          className: option.className,
                          name: option.name,
                          routerLink: option.routerLink,
                          permissionCode: option.permissionCode,
                          title: option.title,
                          content: option.content,
                          status: option.status,
                          icon: option.icon,
                          round: XEUtils.isBoolean(option.round) ? option.round : (btnMode === 'text' ? false : btnRound),
                          circle: XEUtils.isBoolean(option.circle) ? option.circle : (btnMode === 'text' ? false : btnCircle),
                          disabled: option.disabled,
                          loading: option.loading,
                          align: option.align,
                          onClick (params: VxeButtonDefines.ClickEventParams) {
                            downBtnClickEvent(params, option)
                          }
                        })
                      })
                      : [])
                ]
              : [])
          ])
        ])
      }
      if (routerLink) {
        return h(resolveComponent('router-link'), {
          ref: refButton,
          class: ['vxe-button', 'vxe-button--link', `type--${btnMode}`, btnAlign ? `align--${btnAlign}` : '', className ? (XEUtils.isFunction(className) ? className({ $button: $xeButton }) : className) : '', {
            [`size--${vSize}`]: vSize,
            [`theme--${btnStatus}`]: btnStatus,
            'is--round': btnRound,
            'is--circle': btnCircle,
            'is--shadow': shadow,
            'is--disabled': btnDisabled || loading,
            'is--loading': loading
          }],
          title,
          name,
          type: isFormBtn ? type : 'button',
          disabled: btnDisabled || loading,
          to: routerLink,
          onClick: clickEvent,
          onMouseenter: mouseenterEvent,
          onMouseleave: mouseleaveEvent,
          onContextmenu: contextmenuEvent
        }, {
          default () {
            return renderContent()
          }
        })
      }
      return h('button', {
        ref: refButton,
        class: ['vxe-button', `type--${btnMode}`, btnAlign ? `align--${btnAlign}` : '', className ? (XEUtils.isFunction(className) ? className({ $button: $xeButton }) : className) : '', {
          [`size--${vSize}`]: vSize,
          [`theme--${btnStatus}`]: btnStatus,
          'is--round': btnRound,
          'is--circle': btnCircle,
          'is--shadow': shadow,
          'is--disabled': btnDisabled || loading,
          'is--loading': loading
        }],
        title,
        name,
        type: isFormBtn ? type : 'button',
        disabled: btnDisabled || loading,
        onClick: clickEvent,
        onMouseenter: mouseenterEvent,
        onMouseleave: mouseleaveEvent,
        onContextmenu: contextmenuEvent
      }, renderContent())
    }

    $xeButton.renderVN = renderVN

    onMounted(() => {
      if (props.type === 'text') {
        warnLog('vxe.error.delProp', ['[button] type=text', 'mode=text'])
      }

      globalEvents.on($xeButton, 'mousewheel', handleGlobalMousewheelEvent)
      globalEvents.on($xeButton, 'mousedown', handleGlobalMousedownEvent)
      globalEvents.on($xeButton, 'resize', handleGlobalResizeEvent)
    })

    onUnmounted(() => {
      globalEvents.off($xeButton, 'mousewheel')
      globalEvents.off($xeButton, 'mousedown')
      globalEvents.off($xeButton, 'resize')
    })

    return $xeButton
  },
  render () {
    return this.renderVN()
  }
})

export default VxeButtonComponent
