import clsx from 'clsx';
import React, { ForwardedRef } from 'react';
import { Link } from 'react-router-dom';
import { noop } from '../../../helpers/utils';
import { IconName, Icons } from '../../Icons';
import { ButtonContext } from '../Button.model';
import {
  ButtonProps,
  ContextButtonProps,
  NavigationButtonProps,
} from './Button.model';
import classes from './Button.scss';

const ButtonElement: React.ForwardRefRenderFunction<
  HTMLButtonElement | HTMLAnchorElement,
  ButtonProps
> = (
  {
    className,
    customIcon,
    dataTestId,
    disabled = false,
    height,
    icon,
    path,
    width,
    openInNewTab,
    ...rest
  },
  ref: ForwardedRef<HTMLButtonElement | HTMLAnchorElement>,
) => {
  const commonProps = {
    className,
    customIcon,
    dataTestId,
    disabled,
    height,
    icon,
    width,
  };

  return path ? (
    <NavigationButtonElement
      {...commonProps}
      ref={ref as ForwardedRef<HTMLAnchorElement>}
      path={path}
      openInNewTab={openInNewTab}
    />
  ) : (
    <ContextButtonElement
      {...commonProps}
      {...rest}
      ref={ref as ForwardedRef<HTMLButtonElement>}
    />
  );
};

const ContextButtonElement = React.forwardRef<
  HTMLButtonElement,
  ContextButtonProps
>(function ContextButtonElement(
  {
    type = 'button',
    height,
    width,
    buttonContext = ButtonContext.Active,
    disabled = false,
    icon,
    className = '',
    customIcon,
    dataTestId,
    title,
    onButtonClicked = noop,
    onBlur,
  }: ContextButtonProps,
  ref: ForwardedRef<HTMLButtonElement>,
) {
  return (
    <button
      ref={ref}
      className={clsx(
        classes.container,
        {
          [classes.context]: buttonContext === ButtonContext.Context,
          [classes.icon]: buttonContext === ButtonContext.Icon,
          [classes.active]: buttonContext === ButtonContext.Active,
        },
        'button-container',
        className,
      )}
      type={type}
      style={{ height, width }}
      onClick={onButtonClicked}
      disabled={disabled}
      onBlur={onBlur}
      data-test-id={dataTestId ?? 'button'}
      title={title}
    >
      {customIcon ? customIcon : <Icons icon={icon} />}
    </button>
  );
});

const NavigationButtonElement = React.forwardRef<
  HTMLAnchorElement,
  NavigationButtonProps
>(function NavigationButtonElement(
  {
    path,
    height,
    width,
    icon,
    customIcon,
    className = '',
    dataTestId = undefined,
    disabled = false,
    openInNewTab = false,
    title,
  }: NavigationButtonProps,
  ref: ForwardedRef<HTMLAnchorElement>,
) {
  const defaultIcon = openInNewTab ? IconName.External : IconName.ChevronRight;

  return (
    <Link
      ref={ref}
      className={clsx(
        classes.container,
        classes.navigation,
        { [classes.disabled]: disabled },
        'button-container',
        className,
      )}
      to={path}
      style={{ height, width }}
      data-test-id={dataTestId ?? 'button'}
      target={openInNewTab ? '_blank' : undefined}
      title={title}
    >
      {customIcon ? customIcon : <Icons icon={icon ? icon : defaultIcon} />}
    </Link>
  );
});

/**
 * Button which can render an icon.
 * @example
 *   // to render a button element
 *   <Button type="button" icon={IconName.X} />
 *   // to render an anchor element
 *   <Button path="/home" icon={IconName.X} />
 */
export const Button = React.forwardRef<
  HTMLButtonElement | HTMLAnchorElement,
  ButtonProps
>(ButtonElement);
