'use client'

/**
 * Inline "?"" hint icon with a hover tooltip.
 *
 * Use this for any UI element whose meaning isn't obvious from its label —
 * stat boxes, tab names, jargon-y settings. Goal is the same as the (i)
 * dots in Linear / Hyperliquid / Coinglass: small, ignorable, one hover
 * away from a one-line plain-English explanation.
 *
 * Design rules:
 *   * `text` MUST be one short sentence — never paste long docs in here.
 *     If you need a paragraph, you're explaining the wrong thing.
 *   * The icon is intentionally subtle (12 px circle, ink-4 colour). It
 *     should disappear visually until the user actively scans for help.
 *   * The tooltip uses CSS hover positioning — no portals. The only JS is
 *     an on-reveal measurement that clamps the bubble inside the viewport
 *     (a centred bubble on an icon near the screen edge used to hang
 *     off-screen, worst on phones). Trade-off: it's still clipped by the
 *     nearest `overflow:hidden` ancestor. Pages that need tooltips inside
 *     a `<table>` cell should add `overflow: visible` to that row/td.
 *
 * Usage:
 *   <span>Latest cycle <InfoTip text="The single most recent funding payment, in %." /></span>
 *
 *   <InfoTip
 *     text="Last 24h of cycles, averaged. Smooths the noise of one print."
 *     placement="bottom"   // default 'top'
 *   />
 */

import { useRef } from 'react'
import type { CSSProperties } from 'react'

type Placement = 'top' | 'bottom' | 'left' | 'right'

interface Props {
  text: string
  placement?: Placement
  /** Tip max-width in px. Default 240 — fits ~2 short lines. */
  width?: number
  /** Tweak the icon's vertical alignment for fussy contexts. */
  iconStyle?: CSSProperties
}

export default function InfoTip({
  text,
  placement = 'top',
  width = 240,
  iconStyle,
}: Props) {
  const rootRef = useRef<HTMLSpanElement>(null)

  // Clamp the bubble inside the viewport when it's revealed. The bubble is
  // CSS-centred on the icon, so near a screen edge it overflowed off-screen.
  // Measured at shift=0, then the needed horizontal offset is written to the
  // --tip-shift var consumed by the .infotip-top/-bottom transforms.
  function clampIntoViewport() {
    const bubble = rootRef.current?.querySelector<HTMLElement>('.infotip-bubble')
    if (!bubble) return
    bubble.style.setProperty('--tip-shift', '0px')
    const r = bubble.getBoundingClientRect()
    const vw = document.documentElement.clientWidth
    const margin = 8
    let shift = 0
    if (r.left < margin) shift = margin - r.left
    else if (r.right > vw - margin) shift = (vw - margin) - r.right
    if (shift !== 0) bubble.style.setProperty('--tip-shift', `${shift}px`)
  }

  return (
    <span
      ref={rootRef}
      className={`infotip infotip-${placement}`}
      // role=button is a slight overstatement but it lets screen-reader users
      // know there's a thing to tab to. The actual content is in data-tip and
      // also as a regular <span> child for non-CSS-tooltip fallback.
      role="button"
      tabIndex={0}
      aria-label={text}
      style={{ ['--tip-w' as string]: `${width}px`, ...iconStyle }}
      onMouseEnter={clampIntoViewport}
      onFocus={clampIntoViewport}
      onTouchStart={clampIntoViewport}
    >
      <span aria-hidden="true" className="infotip-icon">?</span>
      <span className="infotip-bubble" role="tooltip">{text}</span>
    </span>
  )
}
