import { ElementType, FunctionComponent, useMemo } from 'react';
import { Tooltip, IconButton, IconButtonProps, TooltipProps } from '@mui/material';
import AppIcon from '../AppIcon';
import AppLink from '../AppLink';
import { alpha } from '@mui/material';
import { Props } from '../AppIcon/AppIcon';
import { IconName } from '../AppIcon/config';

export const MUI_ICON_BUTTON_COLORS = [
  'inherit',
  'default',
  'primary',
  'secondary',
  'success',
  'error',
  'info',
  'warning',
];

export interface AppIconButtonProps extends Omit<IconButtonProps, 'color'> {
  color?: string; // Not only 'inherit' | 'default' | 'primary' | 'secondary' | 'success' | 'error' | 'info' | 'warning',
  icon?: IconName | string;
  iconProps?: Partial<Props>;
  // Missing props
  component?: ElementType; // Could be RouterLink, AppLink, <a>, etc.
  to?: string; // Link prop
  href?: string; // Link prop
  openInNewTab?: boolean; // Link prop
  tooltipProps?: Partial<TooltipProps>;
}

/**
 * Renders MUI IconButton with SVG image by given Icon name
 * @param {string} [color] - color of background and hover effect. Non MUI values is also accepted.
 * @param {boolean} [disabled] - the IconButton is not active when true, also the Tooltip is not rendered.
 * @param {string} [href] - external link URI
 * @param {string} [icon] - name of Icon to render inside the IconButton
 * @param {object} [iconProps] - additional props to pass into the AppIcon component
 * @param {boolean} [openInNewTab] - link will be opened in new tab when true
 * @param {string} [size] - size of the button: 'small', 'medium' or 'large'
 * @param {Array<func| object| bool> | func | object} [sx] - additional CSS styles to apply to the button
 * @param {string} [title] - when set, the IconButton is rendered inside Tooltip with this text
 * @param {string} [to] - internal link URI
 * @param {object} [tooltipProps] - additional props to pass into the Tooltip component
 */
const AppIconButton: FunctionComponent<AppIconButtonProps> = ({
  color = 'default',
  component,
  children,
  disabled,
  icon,
  iconProps,
  sx,
  title,
  tooltipProps,
  ...restOfProps
}) => {
  const componentToRender = !component && (restOfProps?.href || restOfProps?.to) ? AppLink : component ?? IconButton;

  const isMuiColor = useMemo(() => MUI_ICON_BUTTON_COLORS.includes(color), [color]);

  const iconButtonToRender = useMemo(() => {
    const colorToRender = isMuiColor ? (color as IconButtonProps['color']) : 'default';
    const sxToRender = {
      ...sx,
      ...(!isMuiColor && {
        color: color,
        ':hover': {
          backgroundColor: alpha(color, 0.04),
        },
      }),
    };
    return (
      <IconButton
        component={componentToRender}
        color={colorToRender}
        disabled={disabled}
        // Named directly on the button (not only via the Tooltip wrap below) so an icon-only button
        // keeps an accessible name even when disabled, when the Tooltip isn't rendered at all. A
        // caller-supplied `aria-label` in restOfProps still wins (spread last).
        aria-label={title}
        sx={sxToRender}
        {...restOfProps}
      >
        <AppIcon icon={icon} {...iconProps} />
        {children}
      </IconButton>
    );
  }, [color, componentToRender, children, disabled, icon, isMuiColor, sx, iconProps, restOfProps, title]);

  // When title is set, wrap the IconButton with Tooltip.
  // Note: when IconButton is disabled the Tooltip is not working, so we don't need it
  return title && !disabled ? (
    <Tooltip title={title} {...tooltipProps}>
      {iconButtonToRender}
    </Tooltip>
  ) : (
    iconButtonToRender
  );
};

export default AppIconButton;
