import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '../lib/cn'
import { Spinner } from '../feedback/spinner'

const buttonVariants = cva(
  // Base: token classes only. Opacity-shift transition guarded by reduced-motion
  // (the motion guard lives in tokens/feedback; transition-opacity is the only
  // allowed interaction motion). No scale/shadow-on-hover (banned).
  'inline-flex items-center justify-center gap-2 rounded font-sans font-medium whitespace-nowrap select-none ' +
    'transition-opacity duration-150 motion-reduce:transition-none ' +
    'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring ' +
    'disabled:opacity-50 disabled:pointer-events-none',
  {
    variants: {
      variant: {
        default: 'bg-accent text-ink-on-accent hover:opacity-90',
        secondary: 'bg-surface text-ink border border-control-border hover:bg-hover',
        ghost: 'bg-transparent text-ink hover:bg-hover',
        destructive: 'bg-danger text-ink-on-accent hover:opacity-90',
        outline: 'bg-transparent text-ink border border-control-border hover:bg-hover',
        link: 'bg-transparent text-accent underline-offset-2 hover:underline p-0',
      },
      size: {
        sm: 'text-body-2 h-8 px-2',
        md: 'text-body-1 h-8 px-4',
        lg: 'text-body-1 h-12 px-6',
        icon: 'h-8 w-8 p-0',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'md',
    },
  },
)

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  variant?: 'default' | 'secondary' | 'ghost' | 'destructive' | 'outline' | 'link'
  size?: 'sm' | 'md' | 'lg' | 'icon'
  loading?: boolean
  asChild?: boolean // Radix Slot composition
}

export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, loading = false, disabled, asChild = false, children, ...props }, ref) => {
    const Comp = asChild ? Slot : 'button'
    const isDisabled = disabled || loading
    return (
      <Comp
        ref={ref}
        className={cn(buttonVariants({ variant, size }), className)}
        disabled={asChild ? undefined : isDisabled}
        aria-disabled={isDisabled || undefined}
        data-loading={loading || undefined}
        {...props}
      >
        {loading && !asChild ? (
          <>
            <Spinner size="sm" />
            {children}
          </>
        ) : (
          children
        )}
      </Comp>
    )
  },
)
Button.displayName = 'Button'

export { buttonVariants }
