import { useEffect, useRef, useState, type ReactElement } from 'react'
import { createPortal } from 'react-dom'
import styles from './Tooltip.module.css'

interface TooltipProps {
  label: string
  children: ReactElement
}

export function Tooltip({ label, children }: TooltipProps) {
  const wrapRef = useRef<HTMLSpanElement>(null)
  const [visible, setVisible] = useState(false)
  const [coords, setCoords] = useState({ top: 0, left: 0 })

  function updatePosition() {
    const el = wrapRef.current
    if (!el) return
    const rect = el.getBoundingClientRect()
    setCoords({
      top: rect.top - 8,
      left: rect.left + rect.width / 2,
    })
  }

  function show() {
    updatePosition()
    setVisible(true)
  }

  function hide() {
    setVisible(false)
  }

  useEffect(() => {
    if (!visible) return

    function onReposition() {
      updatePosition()
    }

    window.addEventListener('scroll', onReposition, true)
    window.addEventListener('resize', onReposition)
    return () => {
      window.removeEventListener('scroll', onReposition, true)
      window.removeEventListener('resize', onReposition)
    }
  }, [visible])

  return (
    <span
      ref={wrapRef}
      className={styles.wrap}
      onMouseEnter={show}
      onMouseLeave={hide}
      onFocusCapture={show}
      onBlurCapture={(e) => {
        if (!wrapRef.current?.contains(e.relatedTarget as Node | null)) {
          hide()
        }
      }}
    >
      {children}
      {visible
        ? createPortal(
            <span
              className={`${styles.tip} ${styles.tipVisible}`}
              role="tooltip"
              style={{ top: coords.top, left: coords.left }}
            >
              {label}
            </span>,
            document.body,
          )
        : null}
    </span>
  )
}
