import React, {
  MouseEvent,
  MutableRefObject,
  PropsWithChildren,
  useEffect,
  useState,
} from "react";
import OSHoverPanel from "./OSHoverPanel";
import { useDebounce } from "primereact/hooks";

interface Props {
  /**
   * Reference to {@link OSHoverPanel} to bind zone events to.
   */
  panelRef: MutableRefObject<OSHoverPanel | null>;

  /**
   * Data to be propagated to {@link OSHoverPanel} for displaying.
   */
  data?: any;
}

/**
 * Component that wraps content with a hover event listener and notifies associated {@link OSHoverPanel}
 *
 * @example
 * const panelRef = useRef<OSHoverPanel | null>(null);
 * ...
 * <OSHoverPanel ref={panelRef} panelBuilder={panel} />
 * ...
 * <OSHoverZone panelRef={panelRef}>
 *  <span>Hover over me!</span>
 * </OSHoverZone>
 * @see {@link OSHoverPanel}
 * @returns
 */
const OSHoverZone: React.FC<PropsWithChildren<Props>> = ({
  panelRef,
  data,
  children,
}) => {
  //Flag whether zone is being hovered or not - debounced slightly to allow user to move over to panel before it closes
  const [, debouncedHoveringContent, setIsHoveringContent] =
    useDebounce<boolean>(false, 300);

  //Currently hovered element (this Zone)
  const [element, setElement] = useState<HTMLDivElement | null>(null);

  //Notifies OSHoverPanel when debounced hover state is changed
  useEffect(() => {
    if (debouncedHoveringContent) {
      panelRef.current?.notifyEnterEvent(element as HTMLElement, data);
    } else {
      panelRef.current?.notifyLeaveEvent();
    }
  }, [debouncedHoveringContent]);

  /**
   * Event of mouse leaving panel - used to correctly hide panel after focus lost
   * @param e associated MouseEvent
   */
  const onMouseEnterContent = (e: MouseEvent<HTMLDivElement>) => {
    setElement(e.currentTarget as HTMLDivElement);
    setIsHoveringContent(true);
  };

  /**
   * Event of mouse leaving panel - used to correctly hide panel after focus lost
   * @param e associated MouseEvent
   */
  const onMouseLeaveContent = () => {
    setIsHoveringContent(false);
  };

  return (
    <>
      <div
        style={{ display: "inline-block" }}
        onMouseEnter={onMouseEnterContent}
        onMouseLeave={onMouseLeaveContent}
        children={children}
      />
    </>
  );
};
export default OSHoverZone;
