import React, { useState, useContext, MouseEvent } from "react";
import MaterialMenu, { MenuProps } from "@material-ui/core/Menu";
import MenuContext from "./context";
import ClickAwayListener from "@material-ui/core/ClickAwayListener";

type ButtonEventFn = (
  event: MouseEvent<HTMLButtonElement | HTMLAnchorElement>
) => void;

interface Props {
  buttonElement: (onClick: {
    onClick: ButtonEventFn;
    onKeyDown: ButtonEventFn;
  }) => React.ReactNode;
  // TODO can we specify the MenuItem[] component type as children?
  children: React.ReactNode;
  anchorOrigin?: MenuProps["anchorOrigin"];
  transformOrigin?: MenuProps["transformOrigin"];
  className?: string;
  onOpen?: () => void;
  onClose?: () => void;
  header?: React.ReactElement;
}

function Menu({
  children,
  className,
  buttonElement,
  anchorOrigin = {
    vertical: "bottom",
    horizontal: "left"
  },
  transformOrigin = {
    vertical: "top",
    horizontal: "left"
  },
  onOpen = () => {},
  onClose = () => {},
  header
}: Props) {
  const [anchorEl, setAnchorEl] = useState(null);
  const [shouldAutoFocus, setShouldAutoFocus] = useState(false);
  const menuContext = useContext(MenuContext);

  function handleClick(event) {
    if (event.type === "click") {
      openWithFocus(false);
    }

    if (
      event.type === "keydown" &&
      (event.key === "Enter" || event.key === "ArrowDown")
    ) {
      openWithFocus(true);
    }

    function openWithFocus(withFocus) {
      setShouldAutoFocus(withFocus);
      setAnchorEl(event.currentTarget);
      onOpen();
    }
  }

  function handleClose() {
    setAnchorEl(null);
    onClose();
  }

  menuContext.registerCloseMenuCallback(handleClose);

  return (
    <ClickAwayListener onClickAway={handleClose}>
      <div className="flex">
        {buttonElement({ onClick: handleClick, onKeyDown: handleClick })}
        <MaterialMenu
          id="nav-unpinned-menu"
          classes={{
            paper: `auik-rounded auik-pointer-events-auto ${className}`,
            list: "auik-py-0"
          }}
          className={"auik-pointer-events-none"}
          anchorEl={anchorEl}
          anchorOrigin={anchorOrigin}
          transformOrigin={transformOrigin}
          getContentAnchorEl={null}
          open={!!anchorEl}
          onClose={handleClose}
          disableScrollLock={true}
          hideBackdrop={true}
          disableBackdropClick
          MenuListProps={{ subheader: header, autoFocusItem: shouldAutoFocus }}
        >
          {children}
        </MaterialMenu>
      </div>
    </ClickAwayListener>
  );
}

export default function MenuWithProvider({ ...props }: Props) {
  const callbacks = [];

  return (
    <MenuContext.Provider
      value={{
        registerCloseMenuCallback: callback => {
          callbacks.push(callback);
        },
        closeMenu: () => {
          callbacks.forEach(callback => callback());
        }
      }}
    >
      <Menu {...props} />
    </MenuContext.Provider>
  );
}
