<template>
  <ul
    :ref="dropdownListWrapperRef"
    :class="dropdownKls"
    :style="rovingFocusGroupRootStyle"
    :tabindex="-1"
    role="menu"
    @blur="onBlur"
    @focus="onFocus"
    @keydown="handleKeydown"
    @mousedown="onMousedown"
  >
    <slot></slot>
  </ul>
</template>
<script lang="ts">
import { computed, defineComponent, inject, unref } from 'vue'
import { composeRefs, composeEventHandlers } from '@element-ultra/utils'
import { EVENT_CODE } from '@element-ultra/shared'
import { FOCUS_TRAP_INJECTION_KEY } from '@element-ultra/components/focus-trap'
import {
  ROVING_FOCUS_COLLECTION_INJECTION_KEY,
  ROVING_FOCUS_GROUP_INJECTION_KEY,
  focusFirst,
} from '@element-ultra/components/roving-focus-group'
import { useNamespace } from '@element-ultra/hooks'
import { DROPDOWN_INJECTION_KEY } from './tokens'
import {
  DROPDOWN_COLLECTION_INJECTION_KEY,
  dropdownMenuProps,
  FIRST_LAST_KEYS,
  LAST_KEYS,
} from './dropdown'
import { useDropdown } from './useDropdown'

export default defineComponent({
  name: 'ElDropdownMenu',
  props: dropdownMenuProps,
  setup(props) {
    const ns = useNamespace('dropdown')
    const { _elDropdownSize } = useDropdown()
    const size = _elDropdownSize.value

    const { focusTrapRef, onKeydown } = inject(
      FOCUS_TRAP_INJECTION_KEY,
      undefined
    )!

    const { contentRef } = inject(DROPDOWN_INJECTION_KEY, undefined)!

    const { collectionRef: dropdownCollectionRef, getItems } = inject(
      DROPDOWN_COLLECTION_INJECTION_KEY,
      undefined
    )!

    const {
      rovingFocusGroupRef,
      rovingFocusGroupRootStyle,
      tabIndex,
      onBlur,
      onFocus,
      onMousedown,
    } = inject(ROVING_FOCUS_GROUP_INJECTION_KEY, undefined)!

    const { collectionRef: rovingFocusGroupCollectionRef } = inject(
      ROVING_FOCUS_COLLECTION_INJECTION_KEY,
      undefined
    )!

    const dropdownKls = computed(() => {
      return [ns.b('menu'), ns.bm('menu', size?.value)]
    })

    const dropdownListWrapperRef = composeRefs(
      contentRef,
      dropdownCollectionRef,
      focusTrapRef,
      rovingFocusGroupRef,
      rovingFocusGroupCollectionRef
    )

    const composedKeydown = composeEventHandlers(
      (e: KeyboardEvent) => {
        props.onKeydown?.(e)
      },
      (e) => {
        const { currentTarget, code, target } = e
        const isKeydownContained = (currentTarget as Node).contains(
          target as Node
        )

        if (isKeydownContained) {
          // TODO: implement typeahead search
        }

        if (EVENT_CODE.tab === code) {
          e.stopImmediatePropagation()
        }

        e.preventDefault()

        if (target !== unref(contentRef)) return
        if (!FIRST_LAST_KEYS.includes(code)) return
        const items = getItems<{ disabled: boolean }>().filter(
          (item) => !item.disabled
        )
        const targets = items.map((item) => item.ref!)
        if (LAST_KEYS.includes(code)) {
          targets.reverse()
        }
        focusFirst(targets)
      }
    )

    const handleKeydown = (e: KeyboardEvent) => {
      composedKeydown(e)
      onKeydown(e)
    }

    return {
      size,
      rovingFocusGroupRootStyle,
      tabIndex,
      dropdownKls,
      dropdownListWrapperRef,
      handleKeydown,
      onBlur,
      onFocus,
      onMousedown,
    }
  },
})
</script>
