import { useEffect, useMemo, useRef, useState } from 'react'

const VIEWPORT_PADDING = 14
const CURSOR_OFFSET = 14
const FALLBACK_WIDTH = 200
const FALLBACK_HEIGHT = 80

export interface DeckTooltipTargetProps {
  'data-tipb': string
  'data-tips'?: string
}

export function useDeckTooltip(tipb: string, tips?: string): DeckTooltipTargetProps {
  return useMemo(() => ({ 'data-tipb': tipb, ...(tips ? { 'data-tips': tips } : {}) }), [tipb, tips])
}

interface TooltipState {
  bold: string
  muted?: string
  clientX: number
  clientY: number
}

function positionWithinViewport(
  clientX: number,
  clientY: number,
  width = FALLBACK_WIDTH,
  height = FALLBACK_HEIGHT,
) {
  const preferredLeft = clientX + CURSOR_OFFSET
  const preferredTop = clientY + CURSOR_OFFSET
  const maxLeft = Math.max(VIEWPORT_PADDING, window.innerWidth - width - VIEWPORT_PADDING)
  const maxTop = Math.max(VIEWPORT_PADDING, window.innerHeight - height - VIEWPORT_PADDING)

  return {
    left: Math.max(VIEWPORT_PADDING, Math.min(preferredLeft, maxLeft)),
    top: Math.max(VIEWPORT_PADDING, Math.min(preferredTop, maxTop)),
  }
}

export function DeckTooltipLayer() {
  const [tooltip, setTooltip] = useState<TooltipState | null>(null)
  const layerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const targetFor = (event: PointerEvent) =>
      event.target instanceof Element ? event.target.closest<HTMLElement>('[data-tipb]') : null

    const show = (event: PointerEvent) => {
      const target = targetFor(event)
      if (!target) return
      setTooltip({
        bold: target.dataset.tipb ?? '',
        muted: target.dataset.tips,
        clientX: event.clientX,
        clientY: event.clientY,
      })
    }
    const move = (event: PointerEvent) => {
      if (!targetFor(event)) return
      setTooltip((current) =>
        current ? { ...current, clientX: event.clientX, clientY: event.clientY } : current,
      )
    }
    const hide = (event: PointerEvent) => {
      if (targetFor(event)) setTooltip(null)
    }

    document.addEventListener('pointerover', show)
    document.addEventListener('pointermove', move)
    document.addEventListener('pointerout', hide)
    return () => {
      document.removeEventListener('pointerover', show)
      document.removeEventListener('pointermove', move)
      document.removeEventListener('pointerout', hide)
    }
  }, [])

  if (!tooltip) return null

  const rect = layerRef.current?.getBoundingClientRect()
  const { left, top } = positionWithinViewport(
    tooltip.clientX,
    tooltip.clientY,
    rect?.width || FALLBACK_WIDTH,
    rect?.height || FALLBACK_HEIGHT,
  )

  return (
    <div
      ref={layerRef}
      role="tooltip"
      className="pointer-events-none fixed z-50 max-w-[200px] rounded-md border border-border bg-surface-raised px-3 py-2 text-xs text-fg shadow-lg"
      style={{ left, top }}
    >
      <strong className="block font-semibold">{tooltip.bold}</strong>
      {tooltip.muted && <span className="mt-0.5 block text-fg-muted">{tooltip.muted}</span>}
    </div>
  )
}
