import type { HTMLAttributes, KeyboardEvent } from 'react';
import { useCallback, useMemo } from 'react';
import type { BadgeShape, BadgeSize, BadgeThickness, BadgeTone, BadgeVariant } from '../types';
import './badge.css';

export type BadgeProps = {
  variant?: BadgeVariant;
  tone?: BadgeTone;
  label?: string;
  icon?: string;
  dismissible?: boolean;
  count?: number | null;
  clickable?: boolean;
  size?: BadgeSize;
  /** When `count` is set, defaults to `pill` (notification style) unless overridden. */
  shape?: BadgeShape;
  thickness?: BadgeThickness;
  customColor?: string;
  disabled?: boolean;
  onDismiss?: () => void;
  onClick?: () => void;
} & Omit<HTMLAttributes<HTMLDivElement>, 'onClick'>;

function normalizeVariant(v: BadgeVariant): Exclude<BadgeVariant, 'error'> {
  return v === 'error' ? 'danger' : v;
}

export function Badge({
  variant = 'default',
  tone = 'solid',
  label = '',
  icon = '',
  dismissible = false,
  count = null,
  clickable = false,
  size = 'md',
  shape: shapeProp,
  thickness = 'normal',
  customColor = '',
  disabled = false,
  onDismiss,
  onClick,
  className,
  onKeyDown,
  tabIndex: tabIndexProp,
  ...rest
}: BadgeProps) {
  const normalizedVariant = normalizeVariant(variant);
  const shape = shapeProp ?? (count !== null ? 'pill' : 'rounded');
  const displayText = useMemo(() => {
    if (count !== null) return count > 999 ? '999+' : String(count);
    return label;
  }, [count, label]);

  const isInteractive = clickable || dismissible;

  const role = clickable || dismissible ? 'button' : 'status';

  const ariaLabelBadge = useMemo(() => {
    if (count !== null) return `Count: ${count}`;
    if (normalizedVariant !== 'default') return `${label}, ${normalizedVariant} badge`;
    return label;
  }, [count, label, normalizedVariant]);

  const tabIndex = tabIndexProp ?? (isInteractive && !disabled ? 0 : undefined);

  const handleBadgeClick = useCallback(() => {
    if (clickable && !disabled) onClick?.();
  }, [clickable, disabled, onClick]);

  const handleDismissClick = useCallback(
    (e: React.MouseEvent) => {
      e.stopPropagation();
      if (!disabled) onDismiss?.();
    },
    [disabled, onDismiss]
  );

  const handleKeyDown = useCallback(
    (e: KeyboardEvent<HTMLDivElement>) => {
      onKeyDown?.(e);
      if (clickable && !disabled && (e.key === 'Enter' || e.key === ' ')) {
        e.preventDefault();
        onClick?.();
      }
    },
    [clickable, disabled, onClick, onKeyDown]
  );

  const handleDismissKeyDown = useCallback((e: KeyboardEvent<HTMLButtonElement>) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      (e.currentTarget as HTMLButtonElement).click();
    }
  }, []);

  const classes = [
    'ccl-badge',
    `ccl-badge--${normalizedVariant}`,
    `ccl-badge--tone-${tone}`,
    `ccl-badge--${size}`,
    `ccl-badge--${shape}`,
    `ccl-badge--thick-${thickness}`,
    clickable ? 'ccl-badge--clickable' : '',
    dismissible ? 'ccl-badge--dismissible' : '',
    disabled ? 'ccl-badge--disabled' : '',
    count !== null ? 'ccl-badge--count' : '',
    className ?? '',
  ]
    .filter(Boolean)
    .join(' ');

  const style =
    normalizedVariant === 'custom' && customColor
      ? ({ backgroundColor: customColor, color: 'white' } as React.CSSProperties)
      : undefined;

  return (
    <div
      className={classes}
      role={role}
      aria-label={ariaLabelBadge}
      tabIndex={tabIndex}
      style={style}
      onClick={handleBadgeClick}
      onKeyDown={handleKeyDown}
      {...rest}
    >
      {icon && count === null ? (
        <span className="ccl-badge__icon ccl-badge__icon--leading" aria-hidden>
          {icon}
        </span>
      ) : null}
      <span className="ccl-badge__content">{displayText}</span>
      {dismissible ? (
        <button
          type="button"
          className="ccl-badge__dismiss"
          aria-label={`Remove ${label || 'badge'}`}
          onClick={handleDismissClick}
          onKeyDown={handleDismissKeyDown}
        >
          <svg className="ccl-badge__dismiss-icon" viewBox="0 0 16 16" aria-hidden focusable="false">
            <path
              d="M2.146 2.146a.5.5 0 0 1 .708 0L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854a.5.5 0 0 1 0-.708z"
              fill="currentColor"
            />
          </svg>
        </button>
      ) : null}
    </div>
  );
}
