import { h, ref, Teleport, onUnmounted } from 'vue'
import { NOOP } from '@vue/shared'
import isServer from '@element-plus/utils/isServer'
import { createGlobalNode, removeGlobalNode } from '@element-plus/utils/global-nodes'

import type { VNode, Ref } from 'vue'

export default (contentRenderer: () => VNode, appendToBody: Ref<boolean>) => {
  const isTeleportVisible = ref(false)

  if (isServer) {
    return {
      isTeleportVisible,
      showTeleport: NOOP,
      hideTeleport: NOOP,
      renderTeleport: NOOP,
    }
  }

  let $el: HTMLElement = null

  const showTeleport = () => {
    isTeleportVisible.value = true
    // this allows the delayed showing strategy since the the content itself could be enterable
    // e.g. el-popper
    if ($el !== null) return

    $el = createGlobalNode()
  }

  const hideTeleport = () => {
    isTeleportVisible.value = false
    if ($el !== null) {
      removeGlobalNode($el)
      $el = null
    }
  }

  const renderTeleport = () => {
    return appendToBody.value !== true
      ? contentRenderer()
      : isTeleportVisible.value
        ? [
          h(
            Teleport,
            { to:  $el },
            contentRenderer(),
          ),
        ]
        : void 0
  }

  onUnmounted(hideTeleport)

  return {
    isTeleportVisible,
    showTeleport,
    hideTeleport,
    renderTeleport,
  }
}