import {
    forwardRef,
    type ButtonHTMLAttributes,
    type ReactNode,
} from "react";
import s from "./Button.module.css";

export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
export type ButtonSize = "sm" | "md" | "lg";

export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>
{
    variant?: ButtonVariant;
    size?: ButtonSize;
    /** 左侧图标（lucide-react 元素或任意 ReactNode）。 */
    leftIcon?: ReactNode;
    /** 右侧图标。 */
    rightIcon?: ReactNode;
    /** 加载态：内容隐藏，覆盖一个旋转圈，按钮自动禁用。 */
    loading?: boolean;
    /** width: 100%。 */
    block?: boolean;
}

const VARIANT_CLASS: Record<ButtonVariant, string> = {
    primary:   s.primary,
    secondary: s.secondary,
    ghost:     s.ghost,
    danger:    s.danger,
};

const SIZE_CLASS: Record<ButtonSize, string> = {
    sm: s.sm,
    md: s.md,
    lg: s.lg,
};

export const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) =>
{
    const {
        variant = "primary",
        size = "md",
        leftIcon, rightIcon, loading, block,
        disabled, className, children, type = "button",
        ...rest
    } = props;

    const cls = [
        s.btn,
        VARIANT_CLASS[variant],
        SIZE_CLASS[size],
        block   ? s.block   : "",
        loading ? s.loading : "",
        className ?? "",
    ].filter(Boolean).join(" ");

    return (
        <button
            ref={ref}
            type={type}
            className={cls}
            disabled={disabled || loading}
            {...rest}
        >
            {leftIcon}
            {/* label 必须包在单个 span 里:button 是 inline-flex + gap,聚珍（Juzhen）
               shim 把文本拆成多段后,每段会成为独立 anonymous flex item,
               flex gap 会被层层叠加,出现「使用 Casdoor 登录」里近一个 CJK
               宽度的异常空隙。包成 span 后整段算 1 个 flex item,shim 仅在
               span 内部插值,gap 只作用于 leftIcon / label / rightIcon 之间。 */}
            <span className={s.label}>{children}</span>
            {rightIcon}
            {loading && <span className={s.spinner} aria-hidden="true" />}
        </button>
    );
});

Button.displayName = "Button";
