import { makeStyles, mergeClasses, tokens, shorthands } from '@fluentui/react-components'
import { Z } from './ui/tokens'

// An instant, theme-styled tooltip implemented entirely in CSS — shown via a
// `:hover` / `:focus-within` visibility toggle on an absolutely-positioned child
// that lives inline in the DOM. We do NOT use Fluent's <Tooltip>, which renders
// a composited popover overlay that flickers on this machine's GPU/driver (see
// memory "aerofetch-gpu-flicker"). No portal, no JS repositioning, no animation,
// no transform/shadow — just a single static paint on hover, so nothing creates
// the overlay surface that flickers. Colors use Fluent's inverted-neutral tokens
// (dark bubble in light mode, light bubble in dark mode) so it matches the theme.
const useStyles = makeStyles({
  wrap: {
    position: 'relative',
    display: 'inline-flex',
    '&:hover [data-hint]': { visibility: 'visible' },
    '&:focus-within [data-hint]': { visibility: 'visible' }
  },
  bubble: {
    position: 'absolute',
    zIndex: Z.tooltip,
    visibility: 'hidden',
    pointerEvents: 'none',
    whiteSpace: 'nowrap',
    padding: '4px 8px',
    fontSize: tokens.fontSizeBase200,
    lineHeight: tokens.lineHeightBase200,
    color: tokens.colorNeutralForegroundInverted,
    backgroundColor: tokens.colorNeutralBackgroundInverted,
    ...shorthands.borderRadius(tokens.borderRadiusMedium)
  },
  top: { bottom: 'calc(100% + 6px)' },
  bottom: { top: 'calc(100% + 6px)' },
  right: { left: 'calc(100% + 6px)', top: '50%', transform: 'translateY(-50%)' },
  left: { right: 'calc(100% + 6px)', top: '50%', transform: 'translateY(-50%)' },
  alignStart: { left: 0 },
  alignEnd: { right: 0 }
})

// `align` only shifts a top/bottom bubble left/right; it does nothing for a
// left/right placement. The union makes that explicit — passing `align` with
// `placement="left"|"right"` is a type error now, instead of being silently
// ignored (L129).
type HintProps = {
  label: string
  children: React.ReactNode
} & (
  | { placement?: 'top' | 'bottom'; align?: 'start' | 'end' }
  | { placement: 'left' | 'right'; align?: never }
)

export function Hint({
  label,
  placement = 'top',
  align = 'start',
  children
}: HintProps): React.JSX.Element {
  const styles = useStyles()
  return (
    <span className={styles.wrap}>
      {children}
      <span
        data-hint
        aria-hidden
        className={mergeClasses(
          styles.bubble,
          placement === 'bottom'
            ? styles.bottom
            : placement === 'right'
              ? styles.right
              : placement === 'left'
                ? styles.left
                : styles.top,
          // start/end alignment only applies to vertical (top/bottom) placements
          (placement === 'top' || placement === 'bottom') &&
            (align === 'end' ? styles.alignEnd : styles.alignStart)
        )}
      >
        {label}
      </span>
    </span>
  )
}
