import { forwardRef } from 'react'
import type { ButtonHTMLAttributes, ReactNode } from 'react'
import { Slot } from 'radix-ui'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'

const iconButtonVariants = cva(
  'flex-none shrink-0 inline-flex items-center justify-center box-border transition-[color,background-color,border-color,box-shadow,transform] duration-200 active:scale-[0.98] focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-border focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer [&>*]:flex [&>*]:items-center [&>*]:justify-center [&>*]:size-full [&>*]:[&>svg]:block [&>*]:[&>svg]:leading-none',
  {
    variants: {
      variant: {
        primary: 'bg-primary text-text-on-primary hover:bg-primary-hover',
        secondary: 'bg-bg-highlight text-text-on-primary hover:bg-bg-highlight-hover',
        tertiary: 'bg-fill-secondary text-text hover:bg-fill',
        ghost: 'bg-transparent text-text-secondary hover:bg-fill-secondary hover:text-text',
        iconOnly: 'bg-transparent text-text-secondary hover:text-text',
        destructive: 'bg-error text-text-on-primary hover:bg-error-hover',
      },
      rounded: {
        square: 'rounded',
        pill: 'rounded-full',
      },
      size: {
        sm: 'h-[var(--control-icon-size-sm)] w-[var(--control-icon-size-sm)] min-h-[var(--control-icon-size-sm)] min-w-[var(--control-icon-size-sm)] p-[var(--control-icon-padding-sm)]',
        md: 'h-[var(--control-icon-size-md)] w-[var(--control-icon-size-md)] min-h-[var(--control-icon-size-md)] min-w-[var(--control-icon-size-md)] p-[var(--control-icon-padding-md)]',
        lg: 'h-[var(--control-icon-size-lg)] w-[var(--control-icon-size-lg)] min-h-[var(--control-icon-size-lg)] min-w-[var(--control-icon-size-lg)] p-[var(--control-icon-padding-lg)]',
      },
    },
    defaultVariants: {
      variant: 'secondary',
      size: 'md',
      rounded: 'square',
    },
  }
)

type IconButtonAccessibleName =
  | { 'aria-label': string; 'aria-labelledby'?: string; title?: string }
  | { 'aria-label'?: string; 'aria-labelledby': string; title?: string }
  | { 'aria-label'?: string; 'aria-labelledby'?: string; title: string }

export type IconButtonProps = Omit<
  ButtonHTMLAttributes<HTMLButtonElement>,
  'aria-label' | 'aria-labelledby' | 'title'
> &
  VariantProps<typeof iconButtonVariants> &
  IconButtonAccessibleName & {
  icon: ReactNode
  asChild?: boolean
}

export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
  (
    {
      variant = 'secondary',
      size = 'md',
      rounded = 'square',
      icon,
      disabled = false,
      asChild = false,
      className,
      ...props
    },
    ref
  ) => {
    const Comp = asChild ? Slot.Root : 'button'
    return (
      <Comp
        ref={ref}
        className={cn(iconButtonVariants({ variant, size, rounded }), className)}
        disabled={disabled}
        {...props}
      >
        <span className="inline-flex shrink-0 size-full items-center justify-center">{icon}</span>
      </Comp>
    )
  }
)
IconButton.displayName = 'IconButton'

export { iconButtonVariants }
