import { memo, useMemo } from 'react';
import type { MouseEventHandler, ReactElement } from 'react';

import { useToggle } from 'react-use';
import { SortableHandle as sortableHandle } from 'react-sortable-hoc';

import clsx from 'clsx';
import noop from 'lodash/noop';

import MuiGrid from '@mui/material/Grid';
import MuiList from '@mui/material/List';
import MuiMenuItem from '@mui/material/MenuItem';
import MuiTypography from '@mui/material/Typography';
import { useTheme } from '@mui/material/styles';

import { ASSETS_URL } from '../../consts/common';
import { Checkbox } from '../@forms/checkbox';
import { CustomIcon } from '../custom-icon';

import MenuItemActionIcon from './MenuItemActionIcon';
import type { MenuItemActionIconProps, MenuItemProps } from './types';
import createClasses from './styles';

const preventDefault: MouseEventHandler<HTMLElement> = e => e.preventDefault();

const SortableHandle = sortableHandle(
  (props: { index: number; styles: ReturnType<typeof createClasses> }) => {
    const { index, styles } = props;

    return (
      <CustomIcon
        data-testid={`sortIcon_${index}`}
        src={`${ASSETS_URL}/icons/icon_drugDrop.svg`}
        className={clsx(styles.icon, styles.dragIcon)}
        id="dragIcon"
      />
    );
  }
);

const MenuItem = ({ modifyMenuItem, ...props }: MenuItemProps) => {
  const modifiedProps: MenuItemProps = modifyMenuItem
    ? { ...props, ...modifyMenuItem(props) }
    : props;

  const {
    id,
    name,
    value,
    multiple,
    selected,
    styles = createClasses({}),
    sortable,
    deletable,
    disabled,
    hidden,
    handleClick,
    handleDelete,
    index = 0,
    showSelectedIcon,
    checkboxProps,
    textNode,
    ariaLabelledby,
    nestedListItems,
    actionIcons = [],
    options,
    classes,
    style,
    ...otherProps
  } = modifiedProps;

  const theme = useTheme();
  const [hover, toggleHover] = useToggle(false);

  const icon = useMemo(() => {
    if (!checkboxProps?.icon) {
      return theme.components?.MuiCheckbox?.defaultProps?.icon;
    }
    return hover ? theme.components?.MuiCheckbox?.defaultProps?.icon : checkboxProps?.icon;
  }, [checkboxProps?.icon, hover, theme.components?.MuiCheckbox?.defaultProps?.icon]);

  const optionsToRender = useMemo(() => options?.filter(item => !item.hidden), [options]);

  const nestedListLabel = useMemo(
    () =>
      textNode || (
        <MuiGrid container direction="row" justifyContent="space-between" alignItems="center">
          <MuiTypography variant="h5">{name}</MuiTypography>
          <MuiTypography variant={'caption2' as 'caption'}>
            {optionsToRender?.filter(item => !!item.selected).length || 0} of{' '}
            {optionsToRender?.length}
          </MuiTypography>
        </MuiGrid>
      ),
    [name, optionsToRender, textNode]
  );

  const { disabled: disabledCheckbox } = checkboxProps || {};
  const key = `key_${id || name}${index}`;

  const menuItemActionIcons = [...actionIcons];

  if (deletable && !nestedListItems) {
    const deleteActionIcon: MenuItemActionIconProps = {
      'data-testid': `deleteIcon_${index}`,
      iconSrc: `${ASSETS_URL}/icons/icon_trash.svg`,
      handleClick: handleDelete
    };
    menuItemActionIcons.push(deleteActionIcon);
  }

  if (selected && !multiple && showSelectedIcon) {
    const singleCheckedIcon: MenuItemActionIconProps = {
      'data-testid': `singleCheckedIcon`,
      iconSrc: `${ASSETS_URL}/icons/icon_checkbox.svg`
    };
    menuItemActionIcons.push(singleCheckedIcon);
  }

  return nestedListItems ? (
    <MuiMenuItem
      tabIndex={0}
      aria-labelledby={ariaLabelledby}
      data-index={index}
      disabled={disabled}
      hidden={hidden}
      key={key}
      className={clsx(
        styles.menuItem,
        classes?.menuItem,
        styles.nestedListWrapper,
        classes?.nestedListWrapper
      )}
      style={style}
      {...otherProps}
    >
      <MuiGrid
        container
        justifyContent="flex-end"
        alignItems="center"
        className={clsx(
          styles.menuItem,
          classes?.menuItem,
          styles.nestedListLabel,
          classes?.nestedListLabel
        )}
      >
        <MuiGrid container item xs>
          {nestedListLabel}
        </MuiGrid>
      </MuiGrid>
      <MuiList
        tabIndex={-1}
        aria-label={`${name}`}
        role="menu"
        className={clsx(styles.nestedListItems, classes?.nestedListItems)}
      >
        {nestedListItems}
      </MuiList>
    </MuiMenuItem>
  ) : (
    <MuiMenuItem
      tabIndex={0}
      aria-labelledby={ariaLabelledby}
      data-index={index}
      disabled={disabled}
      hidden={hidden}
      key={key}
      onClick={disabled || disabledCheckbox ? noop : handleClick?.(name, value)}
      onMouseEnter={toggleHover}
      onMouseLeave={toggleHover}
      className={clsx(
        styles.menuItem,
        classes?.menuItem,
        selected && ['menuItemSelected', styles.menuItemSelected]
      )}
      style={style}
      {...otherProps}
    >
      {sortable && <SortableHandle styles={styles} index={index} />}
      {multiple && (
        <Checkbox
          tabIndex={-1}
          formControlLabelProps={{
            label: (textNode as ReactElement) || name,
            className: styles.formControlLabel,
            onClick: preventDefault,
            classes: {
              label: styles.checkboxLabel
            }
          }}
          checked={!!selected}
          color="default"
          className={styles.checkbox}
          {...(checkboxProps || {})}
          icon={icon}
          size="small"
        />
      )}
      <MuiGrid
        container
        justifyContent="flex-end"
        alignItems="center"
        className={selected && !multiple ? styles.singleSelected : ''}
      >
        {!multiple && (
          <MuiGrid container item xs>
            {textNode || name}
          </MuiGrid>
        )}
        {menuItemActionIcons?.map((actionIconProps, index) => (
          <MenuItemActionIcon
            key={index}
            menuItemProps={{ name, value, styles }}
            {...actionIconProps}
          />
        ))}
      </MuiGrid>
    </MuiMenuItem>
  );
};

export default memo(MenuItem);
