/* eslint-disable react/display-name */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { forwardRef } from 'react';
import { ButtonReferenceType, ButtonProps as NewButtonProps } from './Button.types';
import { PrimitiveAnchor, PrimitiveButton } from '../primitives';
import AvatarLayout from '../avatarLayout';
import ProcessIndicator from '../processIndicator';
import { clsx } from 'clsx';
import { Typography } from '../common';
import Body from '../body';
import type { CommonProps, LegacyButtonProps, ButtonProps } from './LegacyButton';

const Button = forwardRef<ButtonReferenceType, NewButtonProps>(
  (
    {
      as,
      children,
      className,
      size = 'lg',
      href,
      disabled = false,
      priority = 'primary',
      sentiment = 'default',
      addonStart,
      addonEnd,
      // @ts-expect-error NewButtonProps has `type` prop
      type = 'button',
      loading = false,
      block = false,
      v2,
      ...props
    },
    ref,
  ) => {
    const classNames = clsx(
      'wds-Button',
      {
        [`wds-Button--block`]: block,
        [`wds-Button--disabled`]: disabled,
        [`wds-Button--loading`]: loading,
      },
      `wds-Button--${{ sm: 'small', md: 'medium', lg: 'large' }[size]}`,
      `wds-Button--${priority}`,
      `wds-Button--${sentiment}`,
      className,
    );

    const contentClassNames = clsx('wds-Button-content', {
      [`wds-Button-content--loading`]: loading,
    });

    const content = (
      <Body
        as="span"
        type={size === 'sm' ? Typography.BODY_DEFAULT_BOLD : Typography.BODY_LARGE_BOLD}
        className={contentClassNames}
      >
        {loading && (
          <ProcessIndicator
            size={size === 'sm' ? 'xxs' : 'xs'}
            className="wds-Button-loader"
            data-testid="button-loader-indicator"
          />
        )}
        <span
          className="wds-Button-label"
          id={props.id ? `${props.id}_content` : undefined}
          aria-hidden={loading}
        >
          {size === 'lg' ? (
            <span className="wds-Button-labelText">{children}</span>
          ) : (
            <>
              {size === 'md' && addonStart?.type === 'avatar' && addonStart.value && (
                <span className="wds-Button-avatars">
                  <AvatarLayout orientation="horizontal" avatars={addonStart?.value} size={24} />
                </span>
              )}

              {addonStart?.type === 'icon' && addonStart.value && (
                <span className={`wds-Button-icon wds-Button-icon--${size} wds-Button-icon--start`}>
                  {addonStart.value}
                </span>
              )}

              <span className="wds-Button-labelText">{children}</span>

              {addonEnd?.type === 'icon' && addonEnd?.value && (
                <span className={`wds-Button-icon wds-Button-icon--${size} wds-Button-icon--end`}>
                  {addonEnd.value}
                </span>
              )}
            </>
          )}
        </span>
      </Body>
    );

    if ((href && as !== 'button') || as === 'a') {
      return (
        <PrimitiveAnchor
          ref={ref as React.Ref<HTMLAnchorElement>}
          {...(props as any)}
          href={href}
          className={classNames}
          disabled={disabled || loading}
          aria-busy={loading || undefined}
          type={undefined}
        >
          {content}
        </PrimitiveAnchor>
      );
    }

    return (
      <PrimitiveButton
        ref={ref as React.Ref<HTMLButtonElement>}
        {...(props as any)}
        className={classNames}
        disabled={disabled}
        loading={loading}
        type={type}
        href={undefined}
        target={undefined}
      >
        {content}
      </PrimitiveButton>
    );
  },
);

export default Button;

// re-export APIs for backwards compatibility with legacy Button interface
// delete this when migration to new Button is done (or aleast no more deep imports, use following query)
// https://github.com/search?q=org%3Atransferwise+%2Fbuild%5C%2Ftypes%5C%2Fbutton%2F+-is%3Aarchived&type=code
export { CommonProps, LegacyButtonProps as Props, ButtonProps };
