import { onBeforeUnmount, watch } from 'vue'

const FOCUSABLE = [
  'a[href]',
  'button:not([disabled])',
  'textarea:not([disabled])',
  'input:not([disabled])',
  'select:not([disabled])',
  '[tabindex]:not([tabindex="-1"])',
].join(',')

function getFocusableElements(container) {
  return [...container.querySelectorAll(FOCUSABLE)]
    .filter((el) => el.offsetParent !== null || el === document.activeElement)
}

export function useFocusTrap(containerRef, isActive) {
  let previousFocus = null

  function onKeydown(event) {
    if (event.key !== 'Tab' || !containerRef.value) return

    const focusable = getFocusableElements(containerRef.value)
    if (!focusable.length) {
      event.preventDefault()
      return
    }

    const first = focusable[0]
    const last = focusable[focusable.length - 1]

    if (event.shiftKey && document.activeElement === first) {
      event.preventDefault()
      last.focus()
    } else if (!event.shiftKey && document.activeElement === last) {
      event.preventDefault()
      first.focus()
    }
  }

  function activate() {
    previousFocus = document.activeElement
    document.addEventListener('keydown', onKeydown)
    requestAnimationFrame(() => {
      if (!containerRef.value) return
      const focusable = getFocusableElements(containerRef.value)
      ;(focusable[0] ?? containerRef.value).focus()
    })
  }

  function deactivate() {
    document.removeEventListener('keydown', onKeydown)
    if (previousFocus && typeof previousFocus.focus === 'function') {
      previousFocus.focus()
    }
    previousFocus = null
  }

  watch(isActive, (active) => {
    if (active) activate()
    else deactivate()
  }, { immediate: true })

  onBeforeUnmount(deactivate)

  return { deactivate }
}
