import { useEffect, useState } from 'react'

/**
 * Find the active heading of page
 *
 * It selects the top heading by default, and the last item when reached the bottom of page.
 *
 * @param watch - An array of element ids to watch
 * @param single - only one active item at most
 * @returns Active anchor
 */
export function useAnchorObserver(watch: string[], single: boolean): string[] {
  const [activeAnchor, setActiveAnchor] = useState<string[]>([])

  useEffect(() => {
    let visible: string[] = []
    const observer = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          if (entry.isIntersecting && !visible.includes(entry.target.id)) {
            visible = [...visible, entry.target.id]
          } else if (!entry.isIntersecting && visible.includes(entry.target.id)) {
            visible = visible.filter((v) => v !== entry.target.id)
          }
        }

        if (visible.length > 0) setActiveAnchor(visible)
      },
      {
        rootMargin: single ? '-80px 0% -70% 0%' : `-20px 0% -40% 0%`,
        threshold: 1,
      }
    )

    function onScroll(): void {
      const element = document.scrollingElement
      if (!element) return

      if (element.scrollTop === 0 && single) setActiveAnchor(watch.slice(0, 1))
      else if (element.scrollTop + element.clientHeight >= element.scrollHeight - 6) {
        setActiveAnchor((active) => {
          return active.length > 0 && !single
            ? watch.slice(watch.indexOf(active[0]))
            : watch.slice(-1)
        })
      }
    }

    for (const heading of watch) {
      const element = document.getElementById(heading)

      if (element) observer.observe(element)
    }

    onScroll()
    window.addEventListener('scroll', onScroll)
    return () => {
      window.removeEventListener('scroll', onScroll)
      observer.disconnect()
    }
  }, [single, watch])

  return single ? activeAnchor.slice(0, 1) : activeAnchor
}
