import { useCallback, useMemo, useRef } from "react";
import { invariant } from "../../invariant";
import makeDimension from "./get-dimension";
import useLayoutEffect from "../use-isomorphic-layout-effect";
import useUniqueId from "../use-unique-id";

export default function useDraggablePublisher(args) {
  const uniqueId = useUniqueId("draggable");
  const { descriptor, registry, getDraggableRef, canDragInteractiveElements, shouldRespectForcePress, isEnabled } =
    args;
  const options = useMemo(
    () => ({
      canDragInteractiveElements,
      shouldRespectForcePress,
      isEnabled
    }),
    [canDragInteractiveElements, isEnabled, shouldRespectForcePress]
  );
  const getDimension = useCallback(
    (windowScroll) => {
      const el = getDraggableRef();
      invariant(el, "Cannot get dimension when no ref is set");
      return makeDimension(descriptor, el, windowScroll);
    },
    [descriptor, getDraggableRef]
  );
  const entry = useMemo(
    () => ({
      uniqueId,
      descriptor,
      options,
      getDimension
    }),
    [descriptor, getDimension, options, uniqueId]
  );
  const publishedRef = useRef(entry);
  const isFirstPublishRef = useRef(true);

  // mounting and unmounting
  useLayoutEffect(() => {
    registry.draggable.register(publishedRef.current);
    return () => registry.draggable.unregister(publishedRef.current);
  }, [registry.draggable]);

  // updates while mounted
  useLayoutEffect(() => {
    if (isFirstPublishRef.current) {
      isFirstPublishRef.current = false;
      return;
    }
    const last = publishedRef.current;
    publishedRef.current = entry;
    registry.draggable.update(entry, last);
  }, [entry, registry.draggable]);
}
