import { useRef, useCallback, useState, useEffect } from 'react';

/**
 * Hook to attach a ResizeObserver to a DOM node with a callback ref so that
 * the observer can be updated when React reattaches the ref to a new DOM node.
 *
 * ```js
 *
 * import { useResizeObserver } from '@politico/interactive-style';
 * ```
 *
 * @param {Object} options
 *   A configuration object:
 *   - `ref`: A React Ref to attach to the DOM node if you want more control
 *     over which ref is used or need direct access to the ref itself. If this
 *     is not provided, a new ref will be used.
 *   - `initialSize`: A custom size to use before the DOM has been measured
 *     (default `[0,0]`).
 *
 * @returns {any[]}
 */
const useResizeObserver = function useResizeObserver(options = {}) {
  const defaultRef = useRef();
  const {
    ref = defaultRef,
    initialSize = [0, 0]
  } = options;
  const observer = useRef();

  // We keep track of when the ref is reattached with a dummy piece of state
  const [refReattached, setRefReattached] = useState({});
  const [dimensions, setDimensions] = useState(initialSize);

  // Reobserve our node every time React swaps it out for a new one
  useEffect(() => {
    observer.current = new window.ResizeObserver(() => {
      const dom = ref.current;
      if (dom) {
        setDimensions([dom.clientWidth, dom.clientHeight]);
      }
    });
    if (ref.current) {
      observer.current.observe(ref.current);
    }
    return () => {
      observer.current.disconnect();
    };
  }, [refReattached]);

  // Callback ref to monitor when the DOM node changes
  const refCallback = useCallback(node => {
    ref.current = node;
    setRefReattached(() => ({}));
  }, []);
  return [refCallback, dimensions];
};
export default useResizeObserver;