import { type KeyboardEvent, useEffect, useRef } from 'react';

import {
  ClickAwayListener,
  Divider,
  Grow,
  MenuList,
  Paper,
  Popper,
  type PopperProps,
  Stack,
  useTheme,
} from '@mui/material';

import useScrollLock from '../../../hooks/useScrollLock';

import {
  MAX_HEIGHT,
  MAX_WIDTH,
  positionMap,
  transformOriginMap,
} from './constants';
import { type MenuProps } from './types';

export const Menu = ({
  id,
  anchorEl,
  open,
  onClose,
  children,
  sx,
  position = 'center',
  fixedDimensions = true,
  'aria-labelledby': labelledby,
  footer,
  header,
  disableScrollLock = true,
  scrollLockElementId = 'dashboard-layout-content',
  onTransitionEnd,
  disablePortal = false,
}: MenuProps) => {
  const theme = useTheme();

  useScrollLock(disableScrollLock, scrollLockElementId, open);

  const positionValues = positionMap[position];
  const anchorOrigin = [
    positionValues.anchorOrigin.vertical,
    positionValues.anchorOrigin.horizontal,
  ]
    .filter(Boolean)
    .join('-') as PopperProps['placement'];

  const fixedDimensionsSlotSx = {
    maxHeight: MAX_HEIGHT,
    maxWidth: MAX_WIDTH,
  };

  const handleListKeyDown = (
    event: KeyboardEvent,
    reason: 'escapeKeyDown' | 'backdropClick',
  ) => {
    if (event.key === 'Tab') {
      if (!footer) {
        event.preventDefault();
        onClose?.(event, reason);
      }
    } else if (event.key === 'Escape') {
      onClose?.(event, reason);
    }
  };

  const prevOpen = useRef(open);

  useEffect(() => {
    if (prevOpen.current === true && open === false) {
      if (anchorEl && 'focus' in anchorEl) {
        (anchorEl as HTMLElement).focus();
      }
    }

    prevOpen.current = open;
  }, [open, anchorEl]);

  return (
    <Popper
      open={open}
      anchorEl={anchorEl}
      role="menu"
      placement={position === 'top-right' ? 'right-start' : anchorOrigin}
      transition
      onTransitionEnd={onTransitionEnd}
      id={id}
      disablePortal={disablePortal}
      sx={{
        zIndex: 1500,
        ...sx,
      }}
    >
      {({ TransitionProps, placement }) => (
        <Grow
          {...TransitionProps}
          style={{
            transformOrigin: transformOriginMap[placement],
          }}
        >
          <Paper
            sx={{
              boxShadow: theme.shadows[2],
              borderRadius: theme.spacing(2),
              overflow: 'hidden',
              my: 1,
              ...(fixedDimensions && fixedDimensionsSlotSx),
            }}
          >
            <ClickAwayListener
              onClickAway={event => {
                onClose?.(event, 'backdropClick');
              }}
            >
              <MenuList
                autoFocusItem={open}
                onKeyDown={event => handleListKeyDown(event, 'escapeKeyDown')}
                aria-labelledby={labelledby}
                sx={{
                  ...(fixedDimensions && fixedDimensionsSlotSx),
                  overflow: 'auto',
                  p: 0,
                }}
              >
                {header && (
                  <Stack
                    sx={{
                      position: 'sticky',
                      top: 0,
                      zIndex: 1,
                      backgroundColor:
                        theme.palette.new.background.elements.overlay,
                    }}
                  >
                    {header}
                    <Divider
                      sx={{
                        borderBottomWidth: 0.5,
                        color: theme.palette.new.border.neutral.divider,
                      }}
                    />
                  </Stack>
                )}
                {children}
                {footer && (
                  <Stack
                    sx={{
                      position: 'sticky',
                      bottom: 0,
                      zIndex: 1,
                      backgroundColor:
                        theme.palette.new.background.layout.tertiary,
                    }}
                  >
                    <Divider
                      sx={{
                        borderBottomWidth: 0.5,
                        color: theme.palette.new.border.neutral.divider,
                      }}
                    />
                    <Stack
                      sx={{
                        gap: 1,
                        p: 2,
                        flexDirection: 'row',
                        justifyContent: 'space-between',
                        alignItems: 'center',
                      }}
                    >
                      {footer}
                    </Stack>
                  </Stack>
                )}
              </MenuList>
            </ClickAwayListener>
          </Paper>
        </Grow>
      )}
    </Popper>
  );
};

export type { MenuProps };

export default Menu;
