import type { ButtonHTMLAttributes, KeyboardEvent, ReactNode } from 'react';
import { useCallback } from 'react';
import './button.css';

export type ButtonVariant =
  | 'primary'
  | 'secondary'
  | 'success'
  | 'danger'
  | 'warning'
  | 'info'
  | 'light'
  | 'dark'
  | 'link';

export type ButtonSize = 'sm' | 'lg';

/** Visual shown before the label while `loading` is true. */
export type ButtonLoadingIndicator = 'spinner' | 'pulse' | 'dots' | 'dot';

export type ButtonProps = {
  variant?: ButtonVariant;
  size?: ButtonSize;
  outline?: boolean;
  loading?: boolean;
  /** Loader when `loading` is true: spinner (default), bar `pulse`, three `dots`, or single `dot` pulse. */
  loadingIndicator?: ButtonLoadingIndicator;
  ariaLabel?: string;
  ariaDescribedBy?: string;
  ariaExpanded?: boolean;
  ariaPressed?: boolean;
  onClick?: () => void;
  children?: ReactNode;
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>;

export function Button({
  variant = 'primary',
  size,
  outline = false,
  disabled = false,
  loading = false,
  loadingIndicator = 'spinner',
  ariaLabel,
  ariaDescribedBy,
  ariaExpanded,
  ariaPressed,
  onClick,
  children,
  className,
  onKeyDown,
  type = 'button',
  ...rest
}: ButtonProps) {
  const handleClick = useCallback(() => {
    if (!disabled && !loading) onClick?.();
  }, [disabled, loading, onClick]);

  const handleKeyDown = useCallback(
    (e: KeyboardEvent<HTMLButtonElement>) => {
      onKeyDown?.(e);
      if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        handleClick();
      }
    },
    [handleClick, onKeyDown]
  );

  const prefix = outline ? 'ccl-btn-outline' : 'ccl-btn';

  const classes = [
    'ccl-btn',
    `${prefix}-${variant}`,
    size ? `ccl-btn-${size}` : '',
    loading ? 'ccl-btn--loading' : '',
    className ?? '',
  ]
    .filter(Boolean)
    .join(' ');

  return (
    <button
      type={type}
      className={classes}
      disabled={disabled || loading}
      aria-label={ariaLabel}
      aria-describedby={ariaDescribedBy}
      aria-expanded={ariaExpanded}
      aria-pressed={ariaPressed}
      aria-busy={loading ? true : undefined}
      aria-disabled={disabled || loading}
      onClick={handleClick}
      onKeyDown={handleKeyDown}
      {...rest}
    >
      {loading ? (
        loadingIndicator === 'pulse' ? (
          <span className="ccl-btn-pulse" aria-hidden>
            <span className="ccl-btn-pulse__bar" />
            <span className="ccl-btn-pulse__bar" />
            <span className="ccl-btn-pulse__bar" />
          </span>
        ) : loadingIndicator === 'dots' ? (
          <span className="ccl-btn-dots" aria-hidden>
            <span className="ccl-btn-dots__dot" />
            <span className="ccl-btn-dots__dot" />
            <span className="ccl-btn-dots__dot" />
          </span>
        ) : loadingIndicator === 'dot' ? (
          <span className="ccl-btn-dot-pulse" aria-hidden />
        ) : (
          <span className="ccl-btn-spinner" aria-hidden />
        )
      ) : null}
      {children}
    </button>
  );
}
