import { SidePanelModal } from './SidePanelModal';
import React, {
  CSSProperties,
  RefObject,
  useEffect,
  useMemo,
  useState,
} from 'react';
import { createPortal } from 'react-dom';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import { addResizeObserver } from '@wix/bex-core';
import { SidePanelsState } from '../state/SidePanelsState';

export interface WixPatternsModalsContainerProps {
  rootRef?: RefObject<HTMLElement | null | undefined>;
  anchorRef?: RefObject<HTMLElement | null | undefined>;
  zIndex?: CSSProperties['zIndex'];
  state: SidePanelsState;
}

export function WixPatternsModalsContainer(
  props: WixPatternsModalsContainerProps,
) {
  const { state, rootRef, anchorRef, zIndex = 1 } = props;

  const { appendModalsToBody, lodash, useRelativeSidePanel } =
    useWixPatternsContainer();

  const [render, setRender] = useState<{
    top?: number;
    left?: number;
    anchor?: HTMLElement | null;
  }>({});

  useEffect(() => {
    const { container, top } = appendModalsToBody
      ? {
          container: document.body,
          top: 0,
        }
      : {
          container: rootRef?.current ?? document.body,
          top: null,
        };

    const setTop = lodash.throttle(() => {
      const id = window.requestAnimationFrame(() => {
        setRender({
          top: top != null ? top : container.getBoundingClientRect().top,
          left: container.getBoundingClientRect().right,
          anchor: anchorRef?.current ?? container,
        });
      });

      disposers.push(() => window.cancelAnimationFrame(id));
    }, 300);

    const disposers = [addResizeObserver(container, setTop)];

    setTop();

    return () => {
      setTop.cancel();
      disposers.forEach((d) => d?.());
    };
  }, []);

  // creates a new stacking context
  const modalsContainerStyle = useMemo(
    () => ({
      position: 'relative' as const,
      zIndex,
    }),
    [zIndex],
  );

  let child = render.top != null && (
    <SidePanelModal
      state={state}
      top={useRelativeSidePanel ? 0 : render.top}
      left={render.left}
    />
  );

  if (!useRelativeSidePanel) {
    child = (
      <div style={modalsContainerStyle} data-hook="cairo-modals-container">
        {child}
      </div>
    );
  }

  if (render.anchor == null) {
    return null;
  }

  child = createPortal(child, render.anchor);

  return child;
}
