import { isUndefined } from 'lodash';
import { useEffect, useRef } from 'react';
import { flushSync } from 'react-dom';

let checkResize = (cb1: () => void, cb2: () => void, entry: any) => {
  if ('borderBoxSize' in entry) {
    checkResize = (cb1: () => void) => {
      cb1();
    };
  } else {
    checkResize = (cb1: () => void, cb2: () => void) => {
      cb2();
    };
  }
};

export function useResize(target: React.RefObject<Element | null>, cb?: ResizeObserverCallback, disabled = false, skipEmpty = true): void {
  const dataRef = useRef<{
    prevContentRect?: { width: number; height: number };
  }>({});

  if (disabled) {
    dataRef.current.prevContentRect = undefined;
  }

  useEffect(() => {
    if (target.current && !disabled) {
      const observer = new ResizeObserver((entries, observer) => {
        const entry = entries[0];
        checkResize(
          () => {
            if (
              !isUndefined(dataRef.current.prevContentRect) &&
              !(skipEmpty && entry.borderBoxSize[0].blockSize === 0 && entry.borderBoxSize[0].inlineSize === 0) &&
              (dataRef.current.prevContentRect.width !== entry.borderBoxSize[0].inlineSize ||
                dataRef.current.prevContentRect.height !== entry.borderBoxSize[0].blockSize)
            ) {
              flushSync(() => cb?.(entries, observer));
            }
            dataRef.current.prevContentRect = { width: entry.borderBoxSize[0].inlineSize, height: entry.borderBoxSize[0].blockSize };
          },
          () => {
            if (
              !isUndefined(dataRef.current.prevContentRect) &&
              !(skipEmpty && entry.contentRect.width === 0 && entry.contentRect.height === 0) &&
              (dataRef.current.prevContentRect.width !== entry.contentRect.width ||
                dataRef.current.prevContentRect.height !== entry.contentRect.height)
            ) {
              flushSync(() => cb?.(entries, observer));
            }
            dataRef.current.prevContentRect = { width: entry.contentRect.width, height: entry.contentRect.height };
          },
          entry
        );
      });
      observer.observe(target.current);
      return () => {
        observer.disconnect();
      };
    }
  });
}