import { useRef, useEffect, useState, useCallback } from 'react';
import { useSetRecoilState } from 'recoil';
import { breakpointWidth, breakpointHeight } from "../../../atoms/breakpoint/index.js";

/**
 * Hook to initialize a new breakpoint measurement. The default breakpoint
 * measurement, which has a key of `window`, measures the entire inner
 * dimensions of the window (`window.innerWidth` and `window.innerHeight`), but
 * additional breakpoint measurements can be initialized with unique keys. When
 * initializing a custom breakpoint, this hook returns a callback ref that
 * should be attached to the container you wish to measure.
 *
 * Note that our data store initializes the breakpoint atoms automatically, so
 * you likely won't need to use this hook directly in your projects.
 */
const useInitBreakpoint = function useInitBreakpoint(opts = {}) {
  const defaultRef = useRef();
  const {
    key = 'window',
    ref = defaultRef
  } = opts;
  const [refReattached, setRefReattached] = useState({});
  const setWidth = useSetRecoilState(breakpointWidth(key));
  const setHeight = useSetRecoilState(breakpointHeight(key));
  useEffect(() => {
    if (key === 'window') {
      ref.current = window.document.body;
    }
    const getDimensions = () => {
      // Handle the full window width specially so that it doesn't depend on
      // whether or not there's a scrollbar. More specific content wells should
      // measure the actual content well, which _does_ depend on whether
      // there's a scrollbar, but the root window breakpoint is different.
      if (key === 'window') {
        return [window.document.body.offsetWidth, window.innerHeight];
      }
      const dom = ref.current;
      if (dom) {
        return [dom.clientWidth, dom.clientHeight];
      }
      return undefined;
    };
    const observer = new window.ResizeObserver(() => {
      const dimensions = getDimensions();
      if (dimensions) {
        const [width, height] = dimensions;
        setWidth(width);
        setHeight(height);
      }
    });
    if (ref.current) {
      observer.observe(ref.current);
    }
    return () => {
      observer.disconnect();
    };
  }, [refReattached, key, setWidth, setHeight]);
  const refCallback = useCallback(node => {
    ref.current = node;
    setRefReattached(() => ({}));
  }, []);
  if (key !== 'window') return refCallback;
  return undefined;
};
export default useInitBreakpoint;