import type { CSSProperties, ReactNode } from "react";
import { useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { usePlatformLanguage } from "../i18n/LanguageContext";

export type HoverTooltipTone = "default" | "danger";

type TooltipPosition = {
  top: number;
  left: number;
  arrowLeft: number;
  placement: "top" | "bottom";
};

export type HoverTooltipProps = {
  content: ReactNode;
  children: ReactNode;
  className?: string;
  tone?: HoverTooltipTone;
  ariaLabel?: string;
  triggerTabIndex?: number;
  openDelayMs?: number;
};

const VIEWPORT_MARGIN = 12;
const TRIGGER_GAP = 10;

const BASE_TOOLTIP_STYLE: CSSProperties = {
  position: "fixed",
  zIndex: 20000,
  width: "max-content",
  maxWidth: "min(320px, calc(100vw - 48px))",
  borderRadius: 7,
  boxShadow: "var(--shadow-popover)",
  fontSize: 12,
  lineHeight: 1.4,
  padding: "9px 10px",
  whiteSpace: "normal",
  pointerEvents: "none"
};

function clamp(value: number, min: number, max: number) {
  if (max < min) return min;
  return Math.min(Math.max(value, min), max);
}

function tooltipStyleForTone(tone: HoverTooltipTone): CSSProperties {
  if (tone === "danger") {
    return {
      border: "1px solid var(--border-danger-soft)",
      background: "var(--danger-muted-bg)",
      color: "var(--danger-text-tooltip)",
      fontWeight: 700
    };
  }
  return {
    border: "1px solid var(--line-dark)",
    background: "var(--surface)",
    color: "var(--text)",
    fontWeight: 500
  };
}

function arrowStyleForTone(tone: HoverTooltipTone): Pick<CSSProperties, "borderColor" | "background"> {
  if (tone === "danger") {
    return {
      borderColor: "var(--border-danger-soft)",
      background: "var(--danger-muted-bg)"
    };
  }
  return {
    borderColor: "var(--line-dark)",
    background: "var(--surface)"
  };
}

export default function HoverTooltip({
  content,
  children,
  className = "",
  tone = "default",
  ariaLabel,
  triggerTabIndex,
  openDelayMs = 350
}: HoverTooltipProps) {
  const { translateText } = usePlatformLanguage();
  const tooltipId = useId();
  const triggerRef = useRef<HTMLSpanElement | null>(null);
  const tooltipRef = useRef<HTMLDivElement | null>(null);
  const openTimerRef = useRef<number | null>(null);
  const [isOpen, setIsOpen] = useState(false);
  const [position, setPosition] = useState<TooltipPosition | null>(null);

  const clearOpenTimer = useCallback(() => {
    if (openTimerRef.current !== null) {
      window.clearTimeout(openTimerRef.current);
      openTimerRef.current = null;
    }
  }, []);

  const openWithDelay = useCallback(() => {
    if (!content) return;
    clearOpenTimer();
    openTimerRef.current = window.setTimeout(() => {
      openTimerRef.current = null;
      setIsOpen(true);
    }, openDelayMs);
  }, [clearOpenTimer, content, openDelayMs]);

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

  const updatePosition = useCallback(() => {
    const trigger = triggerRef.current;
    const tooltip = tooltipRef.current;
    if (!trigger || !tooltip) return;

    const triggerRect = trigger.getBoundingClientRect();
    const tooltipRect = tooltip.getBoundingClientRect();
    const triggerCenterX = triggerRect.left + triggerRect.width / 2;
    const preferredLeft = triggerCenterX - tooltipRect.width / 2;
    const left = clamp(preferredLeft, VIEWPORT_MARGIN, window.innerWidth - tooltipRect.width - VIEWPORT_MARGIN);
    const topCandidate = triggerRect.top - tooltipRect.height - TRIGGER_GAP;
    const hasRoomAbove = topCandidate >= VIEWPORT_MARGIN;
    const bottomCandidate = triggerRect.bottom + TRIGGER_GAP;
    const top = hasRoomAbove
      ? topCandidate
      : clamp(bottomCandidate, VIEWPORT_MARGIN, window.innerHeight - tooltipRect.height - VIEWPORT_MARGIN);

    setPosition({
      top,
      left,
      arrowLeft: clamp(triggerCenterX - left, 12, tooltipRect.width - 12),
      placement: hasRoomAbove ? "top" : "bottom"
    });
  }, []);

  useLayoutEffect(() => {
    if (!isOpen) {
      setPosition(null);
      return;
    }

    updatePosition();
    const frame = window.requestAnimationFrame(updatePosition);
    return () => window.cancelAnimationFrame(frame);
  }, [isOpen, updatePosition]);

  useEffect(() => {
    if (!isOpen) return undefined;

    const handleScrollOrResize = () => updatePosition();
    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") close();
    };

    window.addEventListener("scroll", handleScrollOrResize, true);
    window.addEventListener("resize", handleScrollOrResize);
    window.addEventListener("keydown", handleKeyDown);

    return () => {
      window.removeEventListener("scroll", handleScrollOrResize, true);
      window.removeEventListener("resize", handleScrollOrResize);
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [close, isOpen, updatePosition]);

  useEffect(() => clearOpenTimer, [clearOpenTimer]);

  const translatedAriaLabel = ariaLabel ? translateText(ariaLabel) : undefined;
  const tooltipStyle: CSSProperties = {
    ...BASE_TOOLTIP_STYLE,
    ...tooltipStyleForTone(tone),
    top: position?.top ?? -9999,
    left: position?.left ?? -9999,
    opacity: position ? 1 : 0
  };
  const arrowColors = arrowStyleForTone(tone);
  const arrowStyle: CSSProperties = position?.placement === "bottom"
    ? {
      position: "absolute",
      left: position.arrowLeft,
      top: 0,
      width: 9,
      height: 9,
      borderLeft: "1px solid",
      borderTop: "1px solid",
      ...arrowColors,
      transform: "translate(-50%, -5px) rotate(45deg)"
    }
    : {
      position: "absolute",
      left: position?.arrowLeft ?? 16,
      top: "100%",
      width: 9,
      height: 9,
      borderRight: "1px solid",
      borderBottom: "1px solid",
      ...arrowColors,
      transform: "translate(-50%, -5px) rotate(45deg)"
    };

  return (
    <>
      <span
        ref={triggerRef}
        className={className}
        tabIndex={triggerTabIndex}
        aria-label={translatedAriaLabel}
        aria-describedby={isOpen ? tooltipId : undefined}
        onMouseEnter={openWithDelay}
        onMouseLeave={close}
        onFocus={openWithDelay}
        onBlur={close}>
        {children}
      </span>
      {isOpen && typeof document !== "undefined" && createPortal(
        <div ref={tooltipRef} id={tooltipId} role="tooltip" style={tooltipStyle}>
          {typeof content === "string" ? translateText(content) : content}
          <span aria-hidden="true" style={arrowStyle} />
        </div>,
        document.body
      )}
    </>
  );
}
