import {
  cloneElement,
  createContext,
  type MouseEvent,
  type MutableRefObject,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';

import Menu from '@design-system/Menu';
import { IconButton } from '@mui/material';
import { IconDotsVertical } from '@tabler/icons-react';

import MenuListOption from './components/MenuListOption';
import { type MenuListProps } from './types';

const menuCloseCallbacks = new Set<() => void>();

type SiblingMenuContextValue = {
  closeCallbacks: Set<() => void>;
  openSubmenusCount: MutableRefObject<number>;
};

const SiblingMenuContext = createContext<SiblingMenuContextValue | null>(null);

const MenuList = ({
  id = '',
  'aria-label': ariaLabel,
  Icon = IconDotsVertical,
  variant,
  size,
  options,
  customButton,
  disableMenu = false,
  fixedDimensions = true,
  position = 'center',
  minWidth = undefined,
  onClose = undefined,
  onClick = undefined,
  slotProps,
}: MenuListProps) => {
  const [openMenu, setOpenMenu] = useState(false);

  const anchorRef = useRef(null);
  const parentContext = useContext(SiblingMenuContext);
  const childCloseCallbacks = useMemo(() => new Set<() => void>(), []);
  const openSubmenusCount = useRef(0);
  const childContextValue = useMemo<SiblingMenuContextValue>(
    () => ({ closeCallbacks: childCloseCallbacks, openSubmenusCount }),
    [childCloseCallbacks],
  );

  const isSubmenu = parentContext !== null;

  const closeMenu = () => {
    setOpenMenu(false);
    onClose?.();
  };

  const closeMenuRef = useRef(closeMenu);
  closeMenuRef.current = closeMenu;
  const openMenuRef = useRef(openMenu);
  openMenuRef.current = openMenu;

  // Let the parent know when this submenu is open so it can ignore click-away
  // events originating from the submenu's Portal-rendered Popper content.
  useEffect(() => {
    if (!parentContext || !openMenu) return;
    parentContext.openSubmenusCount.current++;
    return () => {
      parentContext.openSubmenusCount.current--;
    };
  }, [openMenu, parentContext]);

  // Stable reference for the close-others mechanism, immune to stale closures.
  // Top-level menus call the full closeMenu (with onClose callback).
  // Submenus only reset their own state to avoid cascading onClose to the parent.
  const stableCloseForSet = useMemo(
    () => () => {
      if (!openMenuRef.current) return;
      if (isSubmenu) {
        setOpenMenu(false);
      } else {
        closeMenuRef.current();
      }
    },
    [isSubmenu],
  );

  useEffect(() => {
    const targetSet = isSubmenu
      ? parentContext.closeCallbacks
      : menuCloseCallbacks;
    targetSet.add(stableCloseForSet);
    return () => {
      targetSet.delete(stableCloseForSet);
    };
  }, [isSubmenu, parentContext, stableCloseForSet]);

  const handleMenuOpen = (event: MouseEvent<HTMLButtonElement>) => {
    event.preventDefault();
    event.stopPropagation();

    const targetSet = isSubmenu
      ? parentContext?.closeCallbacks
      : menuCloseCallbacks;
    targetSet.forEach(close => {
      if (close !== stableCloseForSet) close();
    });

    setOpenMenu(true);
  };

  const handleMenuClose = (_event?: unknown, reason?: string) => {
    if (reason === 'backdropClick' && openSubmenusCount.current > 0) return;
    closeMenu();
  };

  const handleMenuItemClick = (event: MouseEvent<HTMLLIElement>) => {
    event.preventDefault();
    event.stopPropagation();
    closeMenu();
  };

  const buttonAria = {
    id: `${id}-menu-button`,
    'aria-label': ariaLabel,
    'aria-controls': `${id}-menu`,
    'aria-haspopup': true,
    'aria-expanded': openMenu ? ('true' as const) : undefined,
  };

  return (
    <SiblingMenuContext.Provider value={childContextValue}>
      <div id={id}>
        {!!customButton &&
          cloneElement(customButton, {
            ref: anchorRef,
            onClick: (event: MouseEvent<HTMLButtonElement>) => {
              customButton.props.onClick?.(event);
              handleMenuOpen(event);
            },
            disabled: disableMenu,
            ...buttonAria,
          })}
        {!customButton && (
          <IconButton
            ref={anchorRef}
            onClick={event => {
              onClick?.(event);
              handleMenuOpen(event);
            }}
            sx={{ color: 'inherit' }}
            variant={variant}
            size={size}
            disabled={disableMenu}
            {...buttonAria}
            {...slotProps?.button}
          >
            <Icon />
          </IconButton>
        )}
        <Menu
          id={`${id}-menu`}
          aria-labelledby={`${id}-menu-button`}
          anchorEl={anchorRef.current}
          onClose={(event, reason) => handleMenuClose(event, reason)}
          open={openMenu}
          sx={{
            ul: { py: 0 },
            '*': { whiteSpace: 'normal' },
          }}
          fixedDimensions={fixedDimensions}
          position={position}
          {...slotProps?.menu}
        >
          {options.map(option => (
            <MenuListOption
              key={option.title}
              onClick={(e: MouseEvent<HTMLLIElement>) => {
                option.onClick?.(e);
                handleMenuItemClick(e);
              }}
              option={option}
              onClose={handleMenuClose}
              disabled={option.disabled}
              minWidth={minWidth}
              menuId={`${id}-menu`}
              slotProps={slotProps?.menuItem}
            />
          ))}
        </Menu>
      </div>
    </SiblingMenuContext.Provider>
  );
};

export type { MenuListProps };

export default MenuList;
