import PropTypes from 'prop-types';
import isUndefined from 'lodash/isUndefined';

import { CircularProgress } from '@mui/material';
import colors from '../Colors';
import { mergeProps } from '../Util';

const extendedColors = {
  did: {
    contained: { backgroundColor: colors.did.primary, color: colors.common.white },
    outlined: { borderColor: colors.did.primary, color: colors.did.primary },
  },
  reverse: {
    contained: { backgroundColor: 'rgba(255, 255, 255, 0.9)', color: colors.grey[900] },
    outlined: { borderColor: colors.grey[900], color: colors.grey[900] },
  },
};

/**
 * @typedef {import('@mui/material').ButtonProps} MuiButtonProps
 * @typedef {{
 *  rounded?: false | true,
 *  loading?: false | true,
 *  forwardedRef?: import('react').ForwardedRef<any>,
 *  color?: MuiButtonProps['color'] | 'reverse' | 'did'
 * }} CustomButtonProps
 * @typedef { CustomButtonProps & Omit<MuiButtonProps, 'color'> } ButtonProps
 */

/**
 * @typedef {React.ForwardRefExoticComponent<React.PropsWithoutRef<ButtonProps> & React.RefAttributes<HTMLButtonElement>>} ButtonComponent
 */

/**
 * @description
 * @export
 * @param {import('@mui/material').ExtendButtonBase<import('@mui/material').ButtonTypeMap<{}, "button">>} BaseComponent
 * @return {ButtonComponent}
 */
export default function wrap(BaseComponent) {
  /**
   *
   * @param {ButtonProps} props
   * @returns
   */
  function WrappedComponent({ ...rawProps }) {
    const props = Object.assign({}, rawProps);
    if (isUndefined(props.rounded)) {
      props.rounded = false;
    }
    if (isUndefined(props.size)) {
      props.size = 'medium';
    }
    if (isUndefined(props.forwardedRef)) {
      props.forwardedRef = null;
    }
    if (isUndefined(props.style)) {
      props.style = {};
    }
    /**
     * @type {ButtonProps}
     */
    const newProps = mergeProps(props, WrappedComponent, ['style']);
    const { children, rounded, loading, disabled, style, forwardedRef, color, ...rest } = newProps;

    const isDisabled = disabled || loading;

    let loadingSize = 16;
    switch (rest.size) {
      case 'small':
        loadingSize = 14;
        break;
      case 'large':
        loadingSize = 18;
        break;
      default:
    }

    // mui v4 只支持 4 种 color 值: default/inherit/primary/secondary (传入这 4 种之外的值会报 warning),
    // 这里扩展 danger/warning/reverse/did 四种 color
    // !! 已升级到 mui v5, error/warning 等 color 已经默认支持, extendedColors 只扩展了 did/reverse
    const matched = extendedColors[color] && extendedColors[color][rest.variant];

    /**
     * @type {import('react').CSSProperties}
     */
    const styles = Object.assign(
      {},
      {
        boxShadow: 'none',
        textTransform: 'capitalize',
        ...matched,
      },
      style
    );
    let _rest = rest;
    if (!matched) {
      // mui button 本身支持的 color 交由 mui 处理
      _rest = { ..._rest, color };
    }
    if (rounded) {
      // styles.borderRadius = { small: 16, medium: 18, large: 20 }[rest.size];
      styles.borderRadius = '100vw';
    }

    return (
      <BaseComponent style={styles} ref={forwardedRef} disabled={isDisabled} {..._rest}>
        {loading && <CircularProgress size={loadingSize} style={{ marginRight: 5 }} />}
        {children}
      </BaseComponent>
    );
  }

  WrappedComponent.propTypes = {
    children: PropTypes.any.isRequired,
    style: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
    size: PropTypes.oneOf(['large', 'medium', 'small']),
    forwardedRef: PropTypes.any,
    rounded: PropTypes.bool,
  };

  // eslint-disable-next-line react/prop-types
  return function WrappedComponentWithRef({ ref, ...props }) {
    return <WrappedComponent {...props} forwardedRef={ref} />;
  };
}
