import { Button as HeadlessButton } from '@headlessui/react'
import { ArrowPathIcon } from '@heroicons/react/24/solid'
import { cva, type VariantProps } from 'class-variance-authority'
import type { ReactNode, ElementType, ComponentPropsWithoutRef } from 'react'
import { twMerge } from 'tailwind-merge'

const buttonVariants = cva(
  'inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
  {
    variants: {
      variant: {
        primary:
          'bg-[#2E2F7C] text-white text-lg hover:bg-[#4C5CA0] hover:shadow transition active:bg-[#6970B4]',
        danger:
          'bg-[#EF4444] text-white text-lg hover:shadow transition active:bg-[#FEE2E2] hover:bg-[#FCA5A5]',
        primaryOutline:
          'border-[3px] bg-[#2E2F7C]  border-white text-white text-lg hover:bg-[#4C5CA0] hover:shadow-lg active:shadow-2xl transition active:bg-[#6970B4]',
        outline:
          'border-[3px] bg-white hover:shadow-lg active:shadow-2xl border-[#2E2F7C] text-[#2E2F7C] hover:text-[#4C5CA0] active:text-[#6970B4] text-lg hover:border-[#4C5CA0] transition active:border-[#6970B4]',
        icon: '',
        link: 'font-semibold text-[#2E2F7C] hover:text-[#4C5CA0] active:text-[#6970B4] transition',
        secondary:
          'hover:bg-[#707FDD]/10 active:bg-[#707FDD]/20 hover:text-[#707FDD] text-[#273240]',
      },
      size: {
        default: 'h-[50px] w-[150px]',
        block: 'h-[50px] w-full',
        icon: 'size-9 rounded-full',
        sm: 'h-8 rounded-md px-3 text-xs',
        lg: 'h-10 rounded-md px-8',
        fit: 'w-fit',
      },
    },
    defaultVariants: {
      variant: 'primary',
      size: 'default',
    },
  },
)

type ButtonBaseProperties = {
  children: ReactNode
  variant?: VariantProps<typeof buttonVariants>['variant']
  size?: VariantProps<typeof buttonVariants>['size']
  className?: string
  isLoading?: boolean
  icon?: ReactNode
}

type PolymorphicReference<C extends ElementType> =
  ComponentPropsWithoutRef<C>['ref']

type ButtonProperties<C extends ElementType> = ButtonBaseProperties & {
  as?: C
  ref?: PolymorphicReference<C>
} & Omit<ComponentPropsWithoutRef<C>, keyof ButtonBaseProperties>

export const Button = <C extends ElementType = 'button'>(
  properties: ButtonProperties<C>,
) => {
  const {
    as,
    children,
    variant,
    size,
    className,
    isLoading = false,
    icon,
    ...restProperties
  } = properties
  const Component = as || HeadlessButton
  const classes = twMerge(buttonVariants({ variant, size, className }))

  return (
    <Component
      className={classes}
      {...restProperties}
    >
      {isLoading ? <ArrowPathIcon className="size-5 animate-spin" /> : icon}
      {children}
    </Component>
  )
}
