import { useEffect, useState, type FocusEvent } from "react";

/**
 * "Peek open on hover or keyboard focus" for a container — the shared brain behind the nav rail
 * and the floating side panels, which sit slim until you point at them or tab into them.
 *
 * Spread `handlers` on the container; `active` is true while the pointer is over it (or any
 * descendant) or focus is inside it.
 *
 * Focus is tracked through the REACT tree, so a portaled menu rendered by a child (the language
 * switcher, the account popover) still counts as "inside" and holds the container open while you
 * use it. The one case that misses: such a portal unmounts while focused, and browsers fire NO blur
 * when a focused node is removed — focus silently falls to the body and `active` would latch on
 * forever. Hence the document-level safety net: when focus has landed nowhere, clear it.
 */
export function useHoverFocusWithin(): {
  active: boolean;
  handlers: {
    onMouseEnter: () => void;
    onMouseLeave: () => void;
    onFocus: () => void;
    onBlur: (e: FocusEvent) => void;
  };
} {
  const [hovered, setHovered] = useState(false);
  const [focused, setFocused] = useState(false);

  useEffect(() => {
    let timer: number | undefined;
    const clearIfFocusLandedNowhere = () => {
      const el = document.activeElement;
      if (!el || el === document.body || el === document.documentElement) setFocused(false);
    };
    // Deferred a tick so activeElement has settled, and rescheduled rather than queued — only the
    // latest state matters.
    const soon = () => {
      window.clearTimeout(timer);
      timer = window.setTimeout(clearIfFocusLandedNowhere, 0);
    };
    document.addEventListener("focusout", soon);
    document.addEventListener("click", soon);
    return () => {
      document.removeEventListener("focusout", soon);
      document.removeEventListener("click", soon);
      window.clearTimeout(timer);
    };
  }, []);

  return {
    active: hovered || focused,
    handlers: {
      onMouseEnter: () => setHovered(true),
      onMouseLeave: () => setHovered(false),
      onFocus: () => setFocused(true),
      onBlur: (e: FocusEvent) => {
        if (!e.currentTarget.contains(e.relatedTarget as Node)) setFocused(false);
      },
    },
  };
}
