import type { ElementType, MouseEventHandler } from 'react';
import { Link } from 'react-router-dom';
import type { ComponentSize } from './types';

type ButtonType = 'solid' | 'outlined' | 'noborder';
type ButtonVariant = 'primary' | 'secondary' | 'important';
type NativeButtonType = 'button' | 'submit' | 'reset';

type ButtonProps = {
    label?: string;
    type: ButtonType;
    variant?: ButtonVariant;
    size?: ComponentSize;
    width?: ComponentSize;
    to?: string;
    htmlType?: NativeButtonType;
    onClick?: MouseEventHandler<HTMLElement>;
    disabled?: boolean;
    icon?: ElementType;
    ariaLabel?: string;
    className?: string;
};

const SIZE_CLASS: Record<ComponentSize, string> = {
    sm: 'h-8 px-3 text-xs',
    md: 'h-10 px-4 text-sm',
    lg: 'h-12 px-5 text-base',
    full: 'h-10 px-4 text-sm',
};

const ICON_ONLY_SIZE_CLASS: Record<ComponentSize, string> = {
    sm: 'h-8 w-8 !p-0',
    md: 'h-10 w-10 !p-0',
    lg: 'h-12 w-12 !p-0',
    full: 'h-10 w-10 !p-0',
};

const ICON_CLASS: Record<ComponentSize, string> = {
    sm: 'h-4 w-4',
    md: 'h-4 w-4',
    lg: 'h-5 w-5',
    full: 'h-4 w-4',
};

const ICON_ONLY_CLASS: Record<ComponentSize, string> = {
    sm: 'h-4 w-4',
    md: 'h-5 w-5',
    lg: 'h-6 w-6',
    full: 'h-5 w-5',
};

const WIDTH_CLASS: Record<ComponentSize, string> = {
    sm: 'max-w-xs',
    md: '',
    lg: 'max-w-md',
    full: 'w-full max-w-none',
};

const TYPE_CLASS: Record<ButtonType, string> = {
    solid: 'btn-solid',
    outlined: 'btn-outlined',
    noborder: 'btn-noborder',
};

const VARIANT_CLASS: Record<ButtonVariant, string> = {
    primary: 'btn-primary',
    secondary: 'btn-secondary',
    important: 'btn-important',
};

function resolveVariant(type: ButtonType, variant?: ButtonVariant): ButtonVariant {
    if (variant) {
        return variant;
    }

    return type === 'solid' ? 'primary' : 'secondary';
}

export function Button({
    label,
    type,
    variant,
    size = 'md',
    width = 'md',
    to,
    htmlType = 'button',
    onClick,
    disabled = false,
    icon: Icon,
    ariaLabel,
    className = '',
}: Readonly<ButtonProps>) {
    const isIconOnly = Icon != null && !label;
    const resolvedVariant = resolveVariant(type, variant);
    const composedClassName = [
        TYPE_CLASS[type],
        VARIANT_CLASS[resolvedVariant],
        isIconOnly ? ICON_ONLY_SIZE_CLASS[size] : SIZE_CLASS[size],
        WIDTH_CLASS[width],
        Icon && label ? 'gap-1.5' : '',
        disabled ? 'pointer-events-none cursor-not-allowed opacity-45 saturate-50' : '',
        className,
    ]
        .join(' ')
        .trim();
    const computedAriaLabel = ariaLabel ?? label;
    const iconClass = `${isIconOnly ? ICON_ONLY_CLASS[size] : ICON_CLASS[size]} shrink-0`;
    const content = (
        <>
            {Icon ? <Icon className={iconClass} aria-hidden="true" /> : null}
            {label ?? null}
        </>
    );

    const handleLinkClick: MouseEventHandler<HTMLElement> = (event) => {
        if (disabled) {
            event.preventDefault();
            return;
        }
        onClick?.(event);
    };

    if (to) {
        return (
            <Link
                to={to}
                onClick={handleLinkClick}
                aria-disabled={disabled}
                aria-label={computedAriaLabel}
                tabIndex={disabled ? -1 : undefined}
                className={composedClassName}
            >
                {content}
            </Link>
        );
    }

    return (
        <button
            type={htmlType}
            onClick={onClick}
            disabled={disabled}
            aria-label={computedAriaLabel}
            className={composedClassName}
        >
            {content}
        </button>
    );
}
