import React, {
  useState,
  useEffect,
  useRef,
  forwardRef,
  ReactNode,
} from "react";

type MenuDirection = "up" | "down";

interface DropdownMenuProps {
  trigger: ReactNode;
  children: (closeMenu: () => void) => ReactNode;
  customClass?: string;
  menuClass?: string;
  direction?: MenuDirection;
}

const DropdownMenu = forwardRef<HTMLDivElement, DropdownMenuProps>(
  ({ trigger, children, customClass = "", menuClass = "", direction }, ref) => {
    const [open, setOpen] = useState(false);
    const [menuDirection, setMenuDirection] = useState<MenuDirection>("down");

    const rootRef = useRef<HTMLDivElement | null>(null);
    const menuRef = useRef<HTMLDivElement | null>(null);

    // expose root ref
    useEffect(() => {
      if (!ref) return;
      if (typeof ref === "function") {
        ref(rootRef.current);
      } else {
        ref.current = rootRef.current;
      }
    }, [ref]);

    // click outside
    useEffect(() => {
      if (!open) return;

      const handleClickOutside = (event: MouseEvent) => {
        if (
          rootRef.current &&
          !rootRef.current.contains(event.target as Node)
        ) {
          setOpen(false);
        }
      };

      document.addEventListener("mousedown", handleClickOutside);
      return () => {
        document.removeEventListener("mousedown", handleClickOutside);
      };
    }, [open]);

    // direction calculation
    useEffect(() => {
      if (!open) return;

      if (direction) {
        setMenuDirection(direction);
        return;
      }

      if (!menuRef.current) return;

      const rect = menuRef.current.getBoundingClientRect();
      const viewportHeight = window.innerHeight;

      if (rect.bottom > viewportHeight) {
        setMenuDirection("up");
      } else {
        setMenuDirection("down");
      }
    }, [open, direction]);

    const toggleMenu = () => setOpen((o) => !o);
    const closeMenu = () => setOpen(false);

    return (
      <div ref={rootRef} className={`dropdown ${customClass}`}>
        <div
          onClick={(e) => {
            e.stopPropagation();
            toggleMenu();
          }}
        >
          {trigger}
        </div>

        {open && (
          <div
            ref={menuRef}
            className={`dropdown-menu ${menuDirection} ${menuClass}`}
          >
            {children(closeMenu)}
          </div>
        )}
      </div>
    );
  }
);

DropdownMenu.displayName = "DropdownMenu";
export default DropdownMenu;
