import * as React from "react";
import { useCallback, useState } from "react";
import { useParams } from "react-router-dom";

import { KeyboardArrowDown as KeyboardArrowDownIcon } from "@mui/icons-material";
import { Button } from "@mui/material";
import Menu from "@mui/material/Menu";

import { enqueueSnackbar } from "notistack";

import { ApiOperation } from "../../api";
import { useApi } from "../../contexts/ApiContext";
import { useI18n } from "../../contexts/I18nContext";
import { useUser } from "../../contexts/UserContext";
import { ContribComponent } from "../../types";
import { hasAccess } from "../../util/has_access";
import { usePage } from "../Page";

import ActionMenuItem from "./ActionMenuItem";

export const ActionMenu: React.FC = () => {
  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
  const [renderedComponent, setRenderedComponent] = useState<ContribComponent>();
  const params = useParams();
  const page = usePage();
  const { user } = useUser();
  const api = useApi();
  const { t } = useI18n();
  const title = useCallback(
    (operation: ApiOperation) => t(operation.component?.title ?? operation.summary ?? operation.id),
    [t],
  );

  const open = Boolean(anchorEl);

  const handleClick = (event: React.MouseEvent<HTMLElement>) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  const handleAction = async (operation: ApiOperation) => {
    if (operation.component != null) {
      let component = operation.component.component;
      setAnchorEl(null);
      if (component instanceof Promise) {
        component = await component;
      }

      setRenderedComponent(() => component);
      return;
    }

    try {
      const action = api.operations[operation.id];

      const response = await action.call({ params });

      if (response.ok) {
        enqueueSnackbar(t(`Completed successfully: ${title(action)}`), {
          variant: "success",
        });
        handleClose();
      } else {
        enqueueSnackbar(t(`Action failed: ${title(action)}`), {
          variant: "error",
        });
        throw response;
      }
    } catch (error) {
      enqueueSnackbar(t("Action failed"), {
        variant: "error",
      });
      console.error(error);
    }
  };

  return (
    <>
      <Menu
        anchorEl={anchorEl}
        open={open}
        slotProps={{
          paper: {
            style: {
              width: "fit-content",
            },
          },
        }}
        onClose={handleClose}
      >
        {page?.contrib
          .filter(
            (operation) =>
              operation.component?.variant === "action" &&
              hasAccess(user, operation.component.permission, operation.component.group),
          )
          .map((operation) => (
            <ActionMenuItem key={operation.id} operation={operation} onAction={handleAction} />
          ))}
      </Menu>

      <Button
        aria-haspopup
        disableElevation
        aria-expanded={open ? "true" : "false"}
        endIcon={<KeyboardArrowDownIcon />}
        sx={{
          borderRadius: 6,
          height: 46,
        }}
        variant="outlined"
        onClick={handleClick}
      >
        Actions
      </Button>

      {renderedComponent &&
        React.createElement(renderedComponent, {
          close: () => setRenderedComponent(undefined),
          data: {},
          refresh: () => {},
        })}
    </>
  );
};

export default ActionMenu;
