'use client';

import React, { useCallback, useEffect, useId, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import styles from './Tooltip.module.css';

interface TooltipProps {
  content: React.ReactNode;
  children: React.ReactNode;
  className?: string;
  underline?: boolean;
}

// Bubble renders into document.body via portal so it escapes any ancestor's
// `overflow: hidden|auto|scroll`. Position is computed from the trigger's
// viewport rect on open and recomputed on scroll/resize while open. The
// trigger references the bubble via aria-describedby when open so screen
// readers announce the tip content alongside the trigger.
export function Tooltip({ content, children, className, underline }: TooltipProps) {
  const triggerRef = useRef<HTMLSpanElement>(null);
  const tooltipId = useId();
  const [isOpen, setIsOpen] = useState(false);
  const [coords, setCoords] = useState<{ top: number; left: number } | null>(null);

  const updatePosition = useCallback(() => {
    const el = triggerRef.current;
    if (!el) return;
    const rect = el.getBoundingClientRect();
    setCoords({
      top: rect.top,
      left: rect.left + rect.width / 2,
    });
  }, []);

  const open = useCallback(() => {
    updatePosition();
    setIsOpen(true);
  }, [updatePosition]);

  const close = useCallback(() => setIsOpen(false), []);

  useEffect(() => {
    if (!isOpen) return;
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') close();
    };
    // Capture so we catch scrolls in any ancestor scroll container, not just window.
    window.addEventListener('scroll', updatePosition, true);
    window.addEventListener('resize', updatePosition);
    window.addEventListener('keydown', onKey);
    return () => {
      window.removeEventListener('scroll', updatePosition, true);
      window.removeEventListener('resize', updatePosition);
      window.removeEventListener('keydown', onKey);
    };
  }, [isOpen, updatePosition, close]);

  const triggerClass = [styles.trigger, underline ? styles.triggerUnderlined : '']
    .filter(Boolean)
    .join(' ');

  return (
    <span
      ref={triggerRef}
      className={`${styles.wrapper} ${className ?? ''}`.trim()}
      onMouseEnter={open}
      onMouseLeave={close}
      onFocus={open}
      onBlur={close}
      aria-describedby={isOpen ? tooltipId : undefined}
    >
      <span className={triggerClass}>{children}</span>
      {isOpen &&
        coords &&
        typeof document !== 'undefined' &&
        createPortal(
          <span
            id={tooltipId}
            className={styles.bubble}
            role="tooltip"
            style={{ top: `${coords.top}px`, left: `${coords.left}px` }}
          >
            {content}
          </span>,
          document.body
        )}
    </span>
  );
}
