import type Stack from "@/util/stack";
import {
  useCallback,
  useEffect,
  useState,
  type Dispatch,
  type SetStateAction,
} from "react";
import { View, viewToHash } from "../scene/consts";
import { animated, useSpring } from "@react-spring/web";
import Icon from "@mdi/react";
import { mdiMenu } from "@mdi/js";

interface MobileMenuProps {
  menuTraversal: Stack<View>;
  setMenuTraversal: Dispatch<SetStateAction<Stack<View>>>;
  pendingView: View | null;
  setPendingView: Dispatch<SetStateAction<View | null>>;
  goPreviousView(): void;
  currentView: View;
}

const AnimatedButton = animated.button as React.ComponentType<
  React.ButtonHTMLAttributes<HTMLButtonElement> & { children?: React.ReactNode }
>;

export const MobileMenu = ({
  menuTraversal,
  setMenuTraversal,
  pendingView,
  setPendingView,
  goPreviousView,
  currentView,
}: MobileMenuProps) => {
  const [menuOpen, setMenuOpen] = useState(false);

  const goToView = useCallback(
    (view: View) => {
      setMenuTraversal((prev) => {
        const next = prev.clone();
        next.push(view);
        return next;
      });
      setPendingView(view);
    },
    [setMenuTraversal, setPendingView]
  );

  useEffect(() => {
    const onPop = () => {
      goPreviousView();
    };
    window.addEventListener("popstate", onPop);
    return () => window.removeEventListener("popstate", onPop);
  }, [goPreviousView]);

  useEffect(() => {
    if (pendingView === null) return;
    window.history.pushState(
      { depth: menuTraversal.size() },
      "",
      viewToHash[pendingView] ? `#${viewToHash[pendingView]}` : "/"
    );
    setPendingView(null);
  }, [menuTraversal, pendingView, setPendingView]);

  const slideProps = useSpring({
    x: menuOpen ? 0 : -128,
    config: { tension: 200, friction: 20 },
  });

  return (
    <div className="w-min">
      <AnimatedButton
        className="m-2 pointer-events-auto"
        onClick={() => setMenuOpen((prev) => !prev)}
      >
        <Icon
          path={mdiMenu}
          size={1.5}
          color="white"
          className="stroke-[0.75] stroke-black"
        />
      </AnimatedButton>
      {/* @ts-expect-error children not typed bug */}
      <animated.div
        style={{
          transform: slideProps.x.to((x) => `translateX(${x}%)`),
        }}
        className="text-white flex flex-col w-min gap-2 text-stroke-2 text-stroke-black paint-sfm ml-2"
      >
        {[
          { label: "Home", view: View.MainView },
          { label: "Projects", view: View.PCView },
          { label: "Socials", view: View.CellphoneView },
          { label: "Resume", view: View.ResumeView },
          { label: "Hobbies", view: View.PrinterView },
          { label: "Credits", view: View.CreditsView },
        ].map(({ label, view }) => (
          <button
            key={view}
            className={`${
              currentView === view ? "bg-neutral-700/50" : "bg-neutral-500/50"
            } px-2 py-1 transition-all duration-300 hover:bg-neutral-700/50 hover:scale-110 rounded pointer-events-auto`}
            onClick={() => goToView(view)}
          >
            {label}
          </button>
        ))}
      </animated.div>
    </div>
  );
};
