import { jsx, jsxs, Fragment } from "react/jsx-runtime";
import { createContext, useContext, useState, useRef, useEffect } from "react";
import { usePopperTooltip } from "react-popper-tooltip";
import isMobile from "is-mobile";
import assert from "assert";
import { createPortal } from "react-dom";
import { TextContext, DefaultTextPropsProvider } from "../Accordion/AccordionItem.mjs";
import { useBraidTheme } from "../../../../side-effects/lib/components/BraidProvider/BraidProvider.mjs";
import { VanillaThemeContainer } from "../BraidProvider/VanillaThemeContainer.mjs";
import { atoms } from "../../css/atoms/atoms.mjs";
import { useSpace } from "../Tabs/Tab.mjs";
import { Box } from "../Box/Box.mjs";
import { verticalOffsetBeforeEntrance, translateZ0, maxWidth, arrow } from "./TooltipRenderer.css.mjs";
import { useIsomorphicLayoutEffect } from "../Tabs/Tabs.mjs";
const BraidPortal = ({ children, container }) => {
  const { vanillaTheme } = useBraidTheme();
  return createPortal(
    /* @__PURE__ */ jsx(TextContext.Provider, { value: null, children: /* @__PURE__ */ jsx(VanillaThemeContainer, { theme: vanillaTheme, setDefaultTextTones: true, children }) }),
    container ?? document.body
  );
};
const useThemeName = () => useBraidTheme().name;
const StaticTooltipContext = createContext(false);
const TooltipTextDefaultsProvider = ({
  children
}) => {
  const themeName = useThemeName();
  return /* @__PURE__ */ jsx(
    DefaultTextPropsProvider,
    {
      size: themeName === "docs" ? "small" : void 0,
      weight: "medium",
      children
    }
  );
};
const borderRadius = "large";
const TooltipContent = ({
  children,
  opacity,
  arrowProps
}) => /* @__PURE__ */ jsx(
  Box,
  {
    display: "flex",
    position: "relative",
    transition: "fast",
    opacity: opacity === 0 ? 0 : void 0,
    className: opacity === 0 ? verticalOffsetBeforeEntrance : translateZ0,
    children: /* @__PURE__ */ jsx(
      Box,
      {
        boxShadow: "large",
        background: "neutral",
        borderRadius,
        padding: "small",
        className: [maxWidth, translateZ0],
        children: /* @__PURE__ */ jsxs(TooltipTextDefaultsProvider, { children: [
          /* @__PURE__ */ jsx(Box, { position: "relative", zIndex: 1, children }),
          /* @__PURE__ */ jsx(
            Box,
            {
              ...arrowProps,
              borderRadius,
              background: "neutral",
              className: arrow
            }
          )
        ] })
      }
    )
  }
);
const validPlacements = ["top", "bottom"];
const normaliseRect = (domRect) => ({
  top: Math.round((domRect == null ? void 0 : domRect.top) || 0),
  left: Math.round((domRect == null ? void 0 : domRect.left) || 0),
  height: Math.round((domRect == null ? void 0 : domRect.height) || 0),
  width: Math.round((domRect == null ? void 0 : domRect.width) || 0)
});
const defaultRect = normaliseRect();
const doesBoundingBoxNeedUpdating = (element, previousRect) => {
  const currentRect = normaliseRect(element == null ? void 0 : element.getBoundingClientRect());
  return JSON.stringify(currentRect) !== JSON.stringify(previousRect);
};
const TooltipRenderer = ({
  id,
  tooltip,
  placement = "top",
  children
}) => {
  assert(
    validPlacements.includes(placement),
    `The 'placement' prop must be one of the following: ${validPlacements.join(
      ", "
    )}`
  );
  const isStatic = useContext(StaticTooltipContext);
  const [controlledVisible, setControlledVisible] = useState(false);
  const [opacity, setOpacity] = useState(0);
  const { grid, space } = useSpace();
  const triggerBoundingBoxRef = useRef(defaultRect);
  const tooltipBoundingRectRef = useRef(defaultRect);
  const {
    visible,
    getTooltipProps,
    setTooltipRef,
    tooltipRef,
    setTriggerRef,
    triggerRef,
    getArrowProps,
    update
  } = usePopperTooltip(
    {
      placement,
      trigger: [isMobile() ? "click" : "hover", "focus"],
      visible: isStatic || controlledVisible,
      onVisibleChange: (newState) => {
        triggerBoundingBoxRef.current = normaliseRect(
          triggerRef == null ? void 0 : triggerRef.getBoundingClientRect()
        );
        tooltipBoundingRectRef.current = normaliseRect(
          tooltipRef == null ? void 0 : tooltipRef.getBoundingClientRect()
        );
        setControlledVisible(newState);
      }
    },
    {
      modifiers: [
        {
          name: "preventOverflow",
          options: {
            padding: space.xsmall * grid
          }
        },
        {
          name: "offset",
          options: {
            offset: [0, space.small * grid]
          }
        },
        {
          name: "arrow",
          options: {
            padding: space.xsmall * grid
          }
        },
        ...isStatic ? [
          {
            name: "flip",
            options: {
              fallbackPlacements: []
            }
          }
        ] : []
      ]
    }
  );
  useIsomorphicLayoutEffect(() => {
    if (controlledVisible && update && (doesBoundingBoxNeedUpdating(triggerRef, triggerBoundingBoxRef.current) || doesBoundingBoxNeedUpdating(tooltipRef, tooltipBoundingRectRef.current))) {
      triggerBoundingBoxRef.current = normaliseRect(
        triggerRef == null ? void 0 : triggerRef.getBoundingClientRect()
      );
      tooltipBoundingRectRef.current = normaliseRect(
        tooltipRef == null ? void 0 : tooltipRef.getBoundingClientRect()
      );
      update();
    }
  });
  useEffect(() => {
    if (visible) {
      const handleKeyDown = ({ key }) => {
        if (key === "Escape") {
          setControlledVisible(false);
        }
      };
      const handleScroll = () => {
        setControlledVisible(false);
      };
      const scrollHandlerOptions = {
        capture: true,
        passive: true
      };
      document.addEventListener("keydown", handleKeyDown);
      document.addEventListener("scroll", handleScroll, scrollHandlerOptions);
      return () => {
        document.removeEventListener("keydown", handleKeyDown);
        document.removeEventListener(
          "scroll",
          handleScroll,
          scrollHandlerOptions
        );
      };
    }
  }, [visible]);
  useEffect(() => {
    if (!triggerRef) {
      return;
    }
    if (visible) {
      const handleFocusIn = (event) => {
        if (event.currentTarget !== triggerRef) {
          setControlledVisible(false);
        }
      };
      document.addEventListener("focusin", handleFocusIn);
      return () => {
        document.removeEventListener("focusin", handleFocusIn);
      };
    }
  }, [triggerRef, visible]);
  assert(
    useEffect(() => {
      if (tooltipRef) {
        assert(
          tooltipRef.querySelectorAll("button, input, select, textarea, a").length === 0,
          "For accessibility reasons, tooltips must not contain interactive elements"
        );
      }
    }, [tooltipRef]) === void 0
  );
  useEffect(() => {
    if (!tooltipRef || !visible) {
      return setOpacity(0);
    }
    const timeout = setTimeout(() => setOpacity(100), isMobile() ? 0 : 250);
    return () => clearTimeout(timeout);
  }, [tooltipRef, visible]);
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    children({
      triggerProps: {
        tabIndex: 0,
        ref: setTriggerRef,
        "aria-describedby": id
      }
    }),
    triggerRef && /* @__PURE__ */ jsx(BraidPortal, { children: /* @__PURE__ */ jsx(
      "div",
      {
        id,
        role: "tooltip",
        hidden: !visible ? true : void 0,
        className: atoms({
          reset: "div",
          zIndex: "notification",
          pointerEvents: "none",
          display: triggerRef && visible ? void 0 : "none"
        }),
        ...visible ? getTooltipProps({
          ref: setTooltipRef
        }) : null,
        children: /* @__PURE__ */ jsx(TooltipContent, { opacity, arrowProps: getArrowProps(), children: tooltip })
      }
    ) })
  ] });
};
export {
  BraidPortal,
  TooltipRenderer,
  useThemeName
};
