import clsx from 'clsx';
import React from 'react';
import type { ButtonHTMLAttributes, ReactNode } from 'react';
import styles from './Button.module.css';

export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
	variant?: 'primary' | 'secondary' | 'danger' | 'dangerSecondary' | 'ghost' | 'link';
	size?: 'sm' | 'md' | 'lg';
	loading?: boolean;
	icon?: ReactNode;
	fitContainer?: boolean;
	fitContent?: boolean;
	square?: boolean;
	children?: ReactNode;
}

const variantClassMap: Record<string, string> = {
	primary: 'primary',
	secondary: 'secondary',
	danger: 'dangerPrimary',
	dangerSecondary: 'dangerSecondary',
	ghost: 'ghost',
	link: 'link',
};

const sizeClassMap: Record<string, string | undefined> = {
	sm: 'compact',
	md: undefined,
	lg: undefined,
};

export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
	(
		{
			variant = 'primary',
			size = 'md',
			loading = false,
			icon,
			fitContainer = false,
			fitContent = false,
			square = false,
			children,
			className,
			disabled,
			type = 'button',
			onClick,
			...props
		},
		ref,
	) => {
		const variantClass = variantClassMap[variant] ?? 'primary';
		const sizeClass = sizeClassMap[size];

		const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
			if (loading) {
				event.preventDefault();
				return;
			}
			onClick?.(event);
		};

		return (
			<button
				ref={ref}
				className={clsx(
					styles.button,
					styles[variantClass],
					{
						[styles.compact]: sizeClass === 'compact',
						[styles.square]: square,
						[styles.fitContainer]: fitContainer,
						[styles.fitContent]: fitContent,
					},
					className,
				)}
				disabled={disabled || loading}
				type={type}
				onClick={handleClick}
				tabIndex={disabled ? -1 : 0}
				{...props}
			>
				<div className={styles.grid}>
					<div className={clsx(styles.iconWrapper, { [styles.hidden]: loading })}>
						{square ? (
							icon
						) : (
							<>
								{icon}
								{children}
							</>
						)}
					</div>
					<div className={clsx(styles.spinnerWrapper, { [styles.hidden]: !loading })}>
						<span className={styles.spinner}>
							<span className={styles.spinnerInner}>
								<span className={styles.spinnerItem} />
								<span className={styles.spinnerItem} />
								<span className={styles.spinnerItem} />
							</span>
						</span>
					</div>
				</div>
			</button>
		);
	},
);

Button.displayName = 'Button';
