import { onBeforeUnmount, onMounted, type Ref } from 'vue'

// 바깥 클릭 / ESC / 스크롤 시 닫기 공용 훅.
// 드롭다운·팝오버·메뉴 등에서 반복되던 document 리스너 등록/해제 로직을 한 곳으로 모은다.
//
// - isOpen:    열림 상태 ref (닫혀 있으면 아무 동작 안 함)
// - close:     닫기 콜백
// - containers: "내부"로 간주할 엘리먼트 ref 목록. 클릭이 이 안이면 무시한다
//               (Teleport 로 body 에 띄운 메뉴는 트리거와 메뉴 ref 를 모두 넣는다)
// - opts.event:        바깥 클릭 감지 이벤트 (기본 'mousedown')
// - opts.esc:          Escape 로 닫을지 (기본 true)
// - opts.closeOnScroll: 스크롤/리사이즈 시 닫을지 — fixed 로 띄운 메뉴 위치 어긋남 방지 (기본 false)
export function useClickOutside(
  isOpen: Ref<boolean>,
  close: () => void,
  containers: Ref<HTMLElement | null>[],
  opts: {
    event?: 'mousedown' | 'click'
    esc?: boolean
    closeOnScroll?: boolean
  } = {},
): void {
  const { event = 'mousedown', esc = true, closeOnScroll = false } = opts

  function onPointer(e: Event): void {
    if (!isOpen.value) return
    const t = e.target as Node
    if (containers.some((r) => r.value?.contains(t))) return
    close()
  }
  function onKey(e: KeyboardEvent): void {
    if (isOpen.value && e.key === 'Escape') close()
  }
  function onScroll(): void {
    if (isOpen.value) close()
  }

  onMounted(() => {
    document.addEventListener(event, onPointer, true)
    if (esc) document.addEventListener('keydown', onKey)
    if (closeOnScroll) {
      window.addEventListener('scroll', onScroll, true)
      window.addEventListener('resize', onScroll)
    }
  })
  onBeforeUnmount(() => {
    document.removeEventListener(event, onPointer, true)
    if (esc) document.removeEventListener('keydown', onKey)
    if (closeOnScroll) {
      window.removeEventListener('scroll', onScroll, true)
      window.removeEventListener('resize', onScroll)
    }
  })
}
