'use client';

import { Icon, type ApprovedIconName } from '@/components/foundation/Icon';
import { classNames } from '@/lib/components/classNames';
import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from 'react';
import styles from './Button.module.css';

export type ButtonIntent =
  | 'primary'
  | 'conversion'
  | 'secondary'
  | 'tertiary'
  | 'ghost'
  | 'destructive'
  | 'link';
export type ButtonSize = 'small' | 'medium' | 'large';

interface CommonButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {
  intent?: ButtonIntent;
  size?: ButtonSize;
  loading?: boolean;
  fullWidth?: boolean;
  leadingIcon?: ApprovedIconName;
  trailingIcon?: ApprovedIconName;
  children: ReactNode;
}

interface IconOnlyButtonProps extends Omit<
  CommonButtonProps,
  'children' | 'leadingIcon' | 'trailingIcon'
> {
  icon: ApprovedIconName;
  'aria-label': string;
  children?: never;
}

export type ButtonProps = CommonButtonProps | IconOnlyButtonProps;

export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(props, ref) {
  const {
    intent = 'primary',
    size = 'medium',
    loading = false,
    fullWidth = false,
    disabled = false,
    className,
    type = 'button',
    ...rest
  } = props;
  const iconOnly = 'icon' in props;
  const content = iconOnly ? (
    <Icon name={props.icon} />
  ) : (
    <>
      {props.leadingIcon ? <Icon name={props.leadingIcon} /> : null}
      <span className={styles.label}>{props.children}</span>
      {props.trailingIcon ? (
        <Icon
          name={props.trailingIcon}
          directionBehavior={
            props.trailingIcon === 'arrow-forward' || props.trailingIcon === 'chevron-forward'
              ? 'mirror'
              : 'fixed'
          }
        />
      ) : null}
    </>
  );

  const nativeProps = { ...rest } as ButtonHTMLAttributes<HTMLButtonElement>;
  delete (nativeProps as Partial<CommonButtonProps>).leadingIcon;
  delete (nativeProps as Partial<CommonButtonProps>).trailingIcon;
  delete (nativeProps as Partial<IconOnlyButtonProps>).icon;

  return (
    <button
      ref={ref}
      type={type}
      className={classNames(
        styles.button,
        styles[intent],
        styles[size],
        iconOnly && styles.iconOnly,
        fullWidth && styles.fullWidth,
        loading && styles.loading,
        className,
      )}
      disabled={disabled || loading}
      aria-busy={loading || undefined}
      data-loading={loading || undefined}
      {...nativeProps}
    >
      {loading ? <Icon name="spinner" className={styles.spinner} /> : null}
      <span className={loading ? styles.loadingContent : undefined}>{content}</span>
    </button>
  );
});
