import { ReactNode, useLayoutEffect, useRef, useState } from "react";
import {
  ConstraintGridRectLayout,
  ConstraintRectLayout,
  RectLayout,
} from "simple-window";
import { RectWindows, useRectWindows } from "simple-window/react";
import "./css.polifill";

const defaultLayout = new RectLayout();

const MIN_WIDTH = 320;
const MIN_HEIGHT = 240;
const RECOMMENDED_WIDTH = 480;
const RECOMMENDED_HEIGHT = 320;

export function FloatingWindowsV2({
  constraintElement,
  children,
}: {
  constraintElement: HTMLElement | null;
  children: ReactNode;
}) {
  return (
    <RectWindows
      layout={defaultLayout}
      defaultConstraintPadding={{ left: 8, right: 8, top: 8, bottom: 8 }}
      zIndexBase={40}
    >
      {children}
      <RectWindowConstraint constraintElement={constraintElement} />
    </RectWindows>
  );
}

function RectWindowConstraint({
  constraintElement,
}: {
  constraintElement: HTMLElement | null;
}) {
  const defaultContainerRef = useRef<HTMLDivElement>(null);
  const collection = useRectWindows();

  const rectLayout = useRef<ConstraintRectLayout>(null);
  const fixedLayout = useRef<ConstraintGridRectLayout>(null);

  const size = useBoundingClientRect(constraintElement);

  useLayoutEffect(() => {
    if (!collection) {
      return;
    }

    if (constraintElement && size && size.width && size.height) {
      if (fixedLayout.current) {
        if (fixedLayout.current.boundingElement !== constraintElement) {
          fixedLayout.current.bindElement(constraintElement);
        }
      } else {
        fixedLayout.current = new ConstraintGridRectLayout(
          1,
          1,
          constraintElement,
          {
            minCols: 1,
            maxCols: 1,
            minRows: 1,
            maxRows: 1,
            suggestionCols: 1,
            suggestionRows: 1,
          }
        ).setRectPaddingPixels({ top: 8, left: 8, right: 8, bottom: 8 });
        fixedLayout.current.allowResize = false;
        fixedLayout.current.allowMove = false;
      }
      collection.layout = fixedLayout.current;
    } else {
      if (!rectLayout.current) {
        rectLayout.current = new ConstraintRectLayout(
          defaultContainerRef?.current ?? window,
          {
            minWidth: MIN_WIDTH,
            minHeight: MIN_HEIGHT,
            maxWidth: window.innerWidth,
            maxHeight: window.innerHeight,
            suggestionWidth: RECOMMENDED_WIDTH,
            suggestionHeight: RECOMMENDED_HEIGHT,
          }
        ).setRectPaddingPixels({ top: 8, left: 8, right: 8, bottom: 8 });
      }
      collection.layout = rectLayout.current;
    }
  }, [constraintElement, collection, size]);

  return (
    <div
      ref={defaultContainerRef}
      className="fixed w-screen h-content-body left-0 top-header pointer-events-none"
    />
  );
}

function useBoundingClientRect(element: Element | null) {
  const [boundingClientRect, setBoundingClientRect] = useState(() =>
    element?.getBoundingClientRect()
  );

  useLayoutEffect(() => {
    if (element) {
      const ro = new ResizeObserver(([entry]) => {
        setBoundingClientRect(entry.contentRect);
      });
      ro.observe(element);
      setBoundingClientRect(element.getBoundingClientRect());

      return () => {
        ro.disconnect();
      };
    }
  }, [element]);

  return boundingClientRect;
}
