import { useWindowSize } from "@solid-primitives/resize-observer";
import { MenuList } from "@suid/material";
import {
  createEffect,
  createSignal,
  type JSX,
  type ParentComponent,
} from "solid-js";
import { ANIM_CURVE_STD } from "./theme";

type Props = {
  open?: boolean;
  onClose?: JSX.EventHandlerUnion<HTMLDialogElement, Event>;
  anchor: () => DOMRect;
};

function adjustMenuPosition(
  rect: DOMRect,
  [left, top]: [number, number],
  { width, height }: { width: number; height: number },
) {
  const ntop = rect.bottom > height ? top - (rect.bottom - height) : top;
  const nleft = rect.right > width ? left - (rect.right - width) : left;
  return [nleft, ntop] as [number, number];
}

const Menu: ParentComponent<Props> = (props) => {
  let root: HTMLDialogElement;
  const [pos, setPos] = createSignal<[number, number]>([0, 0]);
  const windowSize = useWindowSize();

  createEffect(() => {
    if (props.open) {
      const a = props.anchor();
      if (!root.open) {
        root.showModal();
        const rend = root.getBoundingClientRect();

        setPos(adjustMenuPosition(rend, [a.left, a.top], windowSize));

        const overflow = root.style.overflow;
        root.style.overflow = "hidden";
        const duration = (rend.height / 1600) * 1000;
        const easing = ANIM_CURVE_STD;
        const animation = root.animate(
          {
            height: [`${rend.height / 2}px`, `${rend.height}px`],
            width: [`${rend.width / 4 * 3}px`, `${rend.width}px`],
          },
          {
            duration,
            easing,
          },
        );
        animation.addEventListener(
          "finish",
          () => (root.style.overflow = overflow),
        );
      } else {
        setPos(
          adjustMenuPosition(
            root.getBoundingClientRect(),
            [a.left, a.top],
            windowSize,
          ),
        );
      }
    } else {
      animateClose();
    }
  });

  const animateClose = () => {
    const rend = root.getBoundingClientRect();
    const overflow = root.style.overflow;
    root.style.overflow = "hidden";
    const animation = root.animate(
      {
        height: [`${rend.height}px`, `${rend.height / 2}px`],
        width: [`${rend.width}px`, `${rend.width / 4 * 3}px`],
      },
      {
        duration: (rend.height / 2 / 1600) * 1000,
        easing: ANIM_CURVE_STD,
      },
    );
    animation.addEventListener("finish", () => {
      root.style.overflow = overflow;
      root.close();
    });
  };

  return (
    <dialog
      ref={root!}
      onClose={props.onClose}
      onClick={(e) => {
        if (e.target === root) {
          if (props.onClose) {
            if (Array.isArray(props.onClose)) {
              props.onClose[0](props.onClose[1], e);
            } else {
              (
                props.onClose as (
                  event: Event & { currentTarget: HTMLDialogElement },
                ) => void
              )(e);
            }
          }
          e.stopPropagation();
        }
      }}
      style={{
        position: "absolute",
        left: `${pos()[0]}px`,
        top: `${pos()[1]}px`,
        border: "none",
        padding: 0,
        "max-width": "560px",
        width: "max-content",
        /*"min-width": "20vw", */
        "box-shadow": "var(--tutu-shadow-e8)",
      }}
    >
      <div
        style={{
          background: "var(--tutu-color-surface)",
        }}
      >
        <MenuList>{props.children}</MenuList>
      </div>
    </dialog>
  );
};

export default Menu;
