"use client";

import {
  cloneElement,
  isValidElement,
  useEffect,
  useId,
  useRef,
  useState,
  type CSSProperties,
  type ReactElement,
  type ReactNode,
} from "react";

type TooltipSide = "top" | "bottom";

type TooltipTriggerProps = {
  id?: string;
  className?: string;
  "aria-describedby"?: string;
  "aria-expanded"?: boolean;
  onClick?: (event: React.MouseEvent<HTMLElement>) => void;
};

type TooltipProps = {
  content: ReactNode;
  children: ReactElement<TooltipTriggerProps>;
  side?: TooltipSide;
  className?: string;
};

export function Tooltip({
  content,
  children,
  side = "top",
  className = "",
}: TooltipProps) {
  const tooltipId = useId();
  const panelRef = useRef<HTMLDivElement>(null);
  const [open, setOpen] = useState(false);
  const [panelStyle, setPanelStyle] = useState<CSSProperties>({});

  const updatePanelPosition = (trigger: HTMLElement) => {
    const rect = trigger.getBoundingClientRect();
    const gap = 8;

    setPanelStyle({
      top: side === "top" ? undefined : rect.bottom + gap,
      bottom: side === "top" ? window.innerHeight - rect.top + gap : undefined,
      left: rect.left + rect.width / 2,
      transform: "translateX(-50%)",
      maxWidth: Math.min(320, window.innerWidth - 32),
    });
  };

  useEffect(() => {
    if (!open) {
      return;
    }

    const handlePointerDown = (event: MouseEvent) => {
      const target = event.target as Node;

      if (!panelRef.current?.contains(target)) {
        const trigger = document.getElementById(`${tooltipId}-trigger`);

        if (!trigger?.contains(target)) {
          setOpen(false);
        }
      }
    };

    const handleEscape = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setOpen(false);
      }
    };

    const handleReposition = () => {
      const trigger = document.getElementById(`${tooltipId}-trigger`);

      if (trigger) {
        updatePanelPosition(trigger);
      }
    };

    document.addEventListener("mousedown", handlePointerDown);
    document.addEventListener("keydown", handleEscape);
    window.addEventListener("resize", handleReposition);
    window.addEventListener("scroll", handleReposition, true);

    return () => {
      document.removeEventListener("mousedown", handlePointerDown);
      document.removeEventListener("keydown", handleEscape);
      window.removeEventListener("resize", handleReposition);
      window.removeEventListener("scroll", handleReposition, true);
    };
  }, [open, side, tooltipId]);

  if (!isValidElement(children)) {
    return children;
  }

  const toggleTooltip = (trigger: HTMLElement) => {
    setOpen((current) => {
      const next = !current;

      if (next) {
        updatePanelPosition(trigger);
      }

      return next;
    });
  };

  const trigger = cloneElement<TooltipTriggerProps>(children, {
    id: `${tooltipId}-trigger`,
    "aria-describedby": open ? tooltipId : undefined,
    "aria-expanded": open,
    className: `${children.props.className ?? ""} ${className}`.trim(),
    onClick: (event: React.MouseEvent<HTMLElement>) => {
      children.props.onClick?.(event);
      event.stopPropagation();
      toggleTooltip(event.currentTarget);
    },
  });

  return (
    <>
      {trigger}

      {open ? (
        <div
          ref={panelRef}
          id={tooltipId}
          role="tooltip"
          style={panelStyle}
          onClick={(event) => event.stopPropagation()}
          className="fixed z-[120] rounded-2xl border border-border bg-popover px-3 py-2 text-sm leading-6 text-popover-foreground shadow-soft"
        >
          {content}
        </div>
      ) : null}
    </>
  );
}

export type { TooltipProps, TooltipSide };
