import {
  FC,
  Fragment,
  MouseEvent,
  ReactNode,
  Suspense,
  useEffect,
  useState,
} from 'react';

import { IconDots } from '@material-hu/icons/tabler';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';

import HuMenu from '@material-hu/components/design-system/Menu';
import { MenuProps } from '@material-hu/components/design-system/Menu/types';

import { MoreMenuProvider } from 'src/contexts/MoreMenuContext';

const CLOSE_ALL_MENUS_EVENT = 'closeAllMoreMenus';

export type MoreMenuOption = {
  id: string;
  enabled: boolean;
  option: ReactNode;
  closeOnSelect?: boolean;
};

export type MoreMenuProps = {
  id: string;
  label?: string;
  menuOptions: MoreMenuOption[];
  withBackground?: boolean;
  size?: 'small' | 'medium' | 'large';
  menuProps?: Pick<
    MenuProps,
    'fixedDimensions' | 'position' | 'disableScrollLock' | 'sx'
  >;
};

export const MoreMenu: FC<MoreMenuProps> = props => {
  const {
    id,
    label,
    menuOptions,
    withBackground = false,
    size = 'small',
    menuProps,
  } = props;

  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
  const open = Boolean(anchorEl);

  const menuId = `${id}-menu`;
  const buttonId = `${id}-button`;

  useEffect(() => {
    const closeMenuHandler = (e: Event) => {
      const customEvent = e as CustomEvent<{ exceptId: string }>;
      if (customEvent.detail.exceptId !== id) {
        setAnchorEl(null);
      }
    };

    document.addEventListener(CLOSE_ALL_MENUS_EVENT, closeMenuHandler);

    return () => {
      document.removeEventListener(CLOSE_ALL_MENUS_EVENT, closeMenuHandler);
    };
  }, [id]);

  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
    event.preventDefault();
    event.stopPropagation();
    document.dispatchEvent(
      new CustomEvent(CLOSE_ALL_MENUS_EVENT, { detail: { exceptId: id } }),
    );
    setAnchorEl(event.currentTarget);
  };

  const handleClose = (event: MouseEvent<HTMLDivElement>) => {
    event.preventDefault();
    event.stopPropagation();
    setAnchorEl(null);
  };

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

  const filteredOptions = menuOptions.filter(option => option.enabled);

  if (filteredOptions.length === 0) {
    return null;
  }

  return (
    <>
      <IconButton
        id={buttonId}
        aria-label={label}
        aria-controls={menuId}
        aria-haspopup="true"
        aria-expanded={open ? 'true' : undefined}
        size={size}
        sx={{
          '& svg': {
            position: 'relative',
            color: theme =>
              withBackground ? theme.palette.secondary.contrastText : 'inherit',
          },
          '& .background': {
            display: withBackground ? 'reset' : 'none',
            content: '""',
            position: 'absolute',
            width: '100%',
            height: '100%',
            left: 0,
            backgroundColor: theme => theme.palette.secondary.main,
            borderRadius: '50%',
            opacity: 0.5,
          },
        }}
        onClick={handleClick}
      >
        <IconDots />
      </IconButton>
      <HuMenu
        id={menuId}
        anchorEl={anchorEl}
        open={open}
        onClose={handleClose}
        {...menuProps}
        aria-labelledby={buttonId}
        position="right"
      >
        <MoreMenuProvider closeMenu={handleCloseMenuByChild}>
          <Suspense fallback={null}>
            {filteredOptions.map(
              ({ option, id: filteredId, closeOnSelect }) => (
                <Fragment key={filteredId}>
                  {closeOnSelect && (
                    <Stack onClick={handleClose}>{option}</Stack>
                  )}
                  {!closeOnSelect && option}
                </Fragment>
              ),
            )}
          </Suspense>
        </MoreMenuProvider>
      </HuMenu>
    </>
  );
};

export default MoreMenu;
