import classNames from 'clsx';
import * as React from 'react';
import { Link } from 'react-router-dom';

import Icon from '../icon/icon';

import { useButtonStyles } from './useButtonStyles';

import type { ButtonSizes, ButtonThemes } from './useButtonStyles';

interface IButton extends Pick<React.HTMLAttributes<HTMLButtonElement>, 'onClick' | 'onMouseUp'> {
  /** Whether this button expands the width of its container. */
  block?: boolean,
  /** Elements inside the <button> */
  children?: React.ReactNode,
  /** Extra class names for the button. */
  className?: string,
  /** Prevent the button from being clicked. */
  disabled?: boolean,
  /** URL to an SVG icon to render inside the button. */
  icon?: string,
  /** A predefined button size. */
  size?: ButtonSizes,
  /** Text inside the button. Takes precedence over `children`. */
  text?: React.ReactNode,
  /** Makes the button into a navlink, if provided. */
  to?: string,
  /** Styles the button visually with a predefined theme. */
  theme?: ButtonThemes,
  /** Whether this button should submit a form by default. */
  type?: 'button' | 'submit',
}

/** Customizable button element with various themes. */
const Button = React.forwardRef<HTMLButtonElement, IButton>((props, ref): JSX.Element => {
  const {
    block = false,
    children,
    disabled = false,
    icon,
    onClick,
    size = 'md',
    text,
    theme = 'secondary',
    to,
    type = 'button',
    className,
  } = props;

  const themeClass = useButtonStyles({
    theme,
    block,
    disabled,
    size,
  });

  const renderIcon = () => {
    if (!icon) {
      return null;
    }

    return <Icon src={icon} className='mr-2 w-4 h-4' />;
  };

  const handleClick = React.useCallback((event) => {
    if (onClick && !disabled) {
      onClick(event);
    }
  }, [onClick, disabled]);

  const renderButton = () => (
    <button
      className={classNames(themeClass, className)}
      disabled={disabled}
      onClick={handleClick}
      ref={ref}
      type={type}
      data-testid='button'
    >
      {renderIcon()}
      {text || children}
    </button>
  );

  if (to) {
    return (
      <Link to={to} tabIndex={-1} className='inline-flex'>
        {renderButton()}
      </Link>
    );
  }

  return renderButton();
});

export default Button;
