import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'

import { cn } from './utils'

/**
 * Variants:
 *   - `default` — canonical primary action. Equivalent to `primary` (alias).
 *   - `primary` — alias of `default`; provided for callers coming from the
 *     vanilla Button API where `primary` is the canonical name.
 *   - `destructive`, `outline`, `secondary`, `ghost`, `link`, `glass`,
 *     `glass-primary` — see CVA mapping below.
 */
const buttonVariants = cva(
  "inline-flex min-w-0 shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-[8px] border border-transparent font-sans text-[13px] font-semibold leading-none transition-colors duration-150 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-primary/50",
  {
    variants: {
      variant: {
        default: 'border-primary bg-primary text-primary-foreground hover:bg-primary-hover',
        primary: 'border-primary bg-primary text-primary-foreground hover:bg-primary-hover',
        destructive:
          'border-destructive/30 bg-destructive/10 text-accent-rose hover:bg-destructive/15',
        outline: 'border-border bg-transparent text-foreground hover:bg-accent',
        secondary: 'border-border bg-card text-foreground hover:bg-accent',
        ghost: 'text-muted-foreground hover:bg-accent hover:text-foreground',
        link: 'text-primary underline-offset-4 hover:underline hover:text-primary/80',
        glass:
          'border-border-glass bg-glass text-foreground backdrop-blur-[20px] hover:bg-glass-hover',
        'glass-primary':
          'border-primary/30 bg-primary/20 text-primary backdrop-blur-[20px] hover:border-primary',
      },
      size: {
        default: 'min-h-8 px-[14px] py-2',
        sm: 'min-h-7 rounded-[4px] px-2.5 py-[5px] text-[12px]',
        lg: 'min-h-10 px-6',
        icon: 'size-8 p-0',
        'icon-sm': 'size-7 rounded-[4px] p-0',
        'icon-lg': 'size-10 p-0',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
)

/**
 * Shadcn-tone overrides keyed by `variant`.
 *
 * Replaces the `glass`/glow base classes with the canonical shadcn class
 * strings so primitives blend into a Tailwind-v4 / shadcn host app.
 * Sizing classes from `buttonVariants` still apply.
 */
const shadcnButtonBase =
  'inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0'

const shadcnButtonVariantClass: Record<string, string> = {
  default: 'bg-primary text-primary-foreground hover:bg-primary/90',
  destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
  outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
  secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
  ghost: 'hover:bg-accent hover:text-accent-foreground',
  link: 'text-primary underline-offset-4 hover:underline',
  glass: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
  'glass-primary': 'bg-primary text-primary-foreground hover:bg-primary/90',
}

const shadcnButtonSizeClass: Record<string, string> = {
  default: 'h-10 px-4 py-2',
  sm: 'h-9 rounded-md px-3 text-sm',
  lg: 'h-11 rounded-md px-8',
  icon: 'h-10 w-10',
  'icon-sm': 'h-9 w-9',
  'icon-lg': 'h-11 w-11',
}

export type ButtonTone = 'glass' | 'shadcn'

export type ButtonProps = React.ComponentProps<'button'> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean
    /** Show a loading spinner and disable the button */
    loading?: boolean
    /** Icon element to display alongside the label */
    icon?: React.ReactNode
    /** Position the icon before or after the label */
    iconPosition?: 'left' | 'right'
    /**
     * Visual tone. `'glass'` (default) emits the library's gradient/glow
     * styling. `'shadcn'` emits canonical shadcn / Tailwind-v4 classes so
     * the button blends into a shadcn host app.
     */
    tone?: ButtonTone
  }

function Button({
  className,
  variant = 'default',
  size = 'default',
  asChild = false,
  loading = false,
  icon,
  iconPosition = 'left',
  tone = 'glass',
  disabled,
  children,
  ...props
}: ButtonProps) {
  const Comp = asChild ? Slot : 'button'
  const isDisabled = disabled || loading

  const variantKey = variant ?? 'default'
  const sizeKey = size ?? 'default'

  const classes =
    tone === 'shadcn'
      ? cn(
          shadcnButtonBase,
          shadcnButtonVariantClass[variantKey] ?? shadcnButtonVariantClass.default,
          shadcnButtonSizeClass[sizeKey] ?? shadcnButtonSizeClass.default,
          className
        )
      : cn(buttonVariants({ variant, size, className }))

  return (
    <Comp
      data-slot="button"
      data-variant={variant}
      data-size={size}
      data-tone={tone}
      disabled={isDisabled}
      aria-disabled={isDisabled || undefined}
      aria-busy={loading || undefined}
      className={classes}
      {...props}
    >
      {loading ? (
        <>
          <svg className="size-4 animate-spin" viewBox="0 0 24 24" fill="none" aria-hidden="true">
            <circle
              className="opacity-25"
              cx="12"
              cy="12"
              r="10"
              stroke="currentColor"
              strokeWidth="4"
            />
            <path
              className="opacity-75"
              fill="currentColor"
              d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
            />
          </svg>
          <span className="sr-only">Loading</span>
          {children}
        </>
      ) : (
        <>
          {icon && iconPosition === 'left' && icon}
          {children}
          {icon && iconPosition === 'right' && icon}
        </>
      )}
    </Comp>
  )
}

export { Button, buttonVariants }
