import * as React from 'react'
import { motion } from 'framer-motion'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
import { CloseLargeLine } from './icons-inline'

const tagVariants = cva(
  'inline-flex items-center justify-center gap-1.5 rounded-md border px-2.5 py-0.5 text-xs font-medium transition-colors whitespace-nowrap cursor-pointer group',
  {
    variants: {
      appearance: { filled: '', outline: 'bg-transparent' },
      color: {
        primary: '',
        success: '',
        error: '',
        warning: '',
        info: '',
        link: '',
        pink: '',
        purple: '',
        yellow: '',
        orange: '',
        teal: '',
        blue: '',
        mauve: '',
        slate: '',
        lavender: '',
        sage: '',
      },
    },
    compoundVariants: [
      { appearance: 'filled', color: 'primary', className: 'border-transparent bg-primary text-text-on-primary hover:bg-primary-hover' },
      { appearance: 'filled', color: 'success', className: 'border-transparent bg-success-bg text-success border-success-border hover:bg-success-bg-hover' },
      { appearance: 'filled', color: 'error', className: 'border-transparent bg-error-bg text-error border-error-border hover:bg-error-bg-hover' },
      { appearance: 'filled', color: 'warning', className: 'border-transparent bg-warning-bg text-warning border-warning-border hover:bg-warning-bg-hover' },
      { appearance: 'filled', color: 'info', className: 'border-transparent bg-info-bg text-info border-info-border hover:bg-info-bg-hover' },
      { appearance: 'filled', color: 'link', className: 'border-transparent bg-transparent text-link underline-offset-4 hover:underline hover:text-link' },
      { appearance: 'filled', color: 'pink', className: 'border-transparent bg-pink-bg text-pink hover:bg-pink-bg-hover' },
      { appearance: 'filled', color: 'purple', className: 'border-transparent bg-purple-bg text-purple hover:bg-purple-bg-hover' },
      { appearance: 'filled', color: 'yellow', className: 'border-transparent bg-yellow-bg text-yellow hover:bg-yellow-bg-hover' },
      { appearance: 'filled', color: 'orange', className: 'border-transparent bg-orange-bg text-orange hover:bg-orange-bg-hover' },
      { appearance: 'filled', color: 'teal', className: 'border-transparent bg-teal-bg text-teal hover:bg-teal-bg-hover' },
      { appearance: 'filled', color: 'blue', className: 'border-transparent bg-blue-bg text-blue hover:bg-blue-bg-hover' },
      { appearance: 'filled', color: 'mauve', className: 'border-transparent bg-mauve-bg text-mauve hover:bg-mauve-bg-hover' },
      { appearance: 'filled', color: 'slate', className: 'border-transparent bg-slate-bg text-slate hover:bg-slate-bg-hover' },
      { appearance: 'filled', color: 'lavender', className: 'border-transparent bg-lavender-bg text-lavender hover:bg-lavender-bg-hover' },
      { appearance: 'filled', color: 'sage', className: 'border-transparent bg-sage-bg text-sage hover:bg-sage-bg-hover' },
      { appearance: 'outline', color: 'primary', className: 'border-primary-border text-primary hover:bg-primary-bg' },
      { appearance: 'outline', color: 'success', className: 'border-success-border text-success hover:bg-success-bg' },
      { appearance: 'outline', color: 'error', className: 'border-error-border text-error hover:bg-error-bg' },
      { appearance: 'outline', color: 'warning', className: 'border-warning-border text-warning hover:bg-warning-bg' },
      { appearance: 'outline', color: 'info', className: 'border-info-border text-info hover:bg-info-bg' },
      { appearance: 'outline', color: 'link', className: 'border-transparent text-link underline-offset-4 hover:underline hover:text-link' },
      { appearance: 'outline', color: 'pink', className: 'border-pink text-pink hover:bg-pink-bg' },
      { appearance: 'outline', color: 'purple', className: 'border-purple text-purple hover:bg-purple-bg' },
      { appearance: 'outline', color: 'yellow', className: 'border-yellow text-yellow hover:bg-yellow-bg' },
      { appearance: 'outline', color: 'orange', className: 'border-orange text-orange hover:bg-orange-bg' },
      { appearance: 'outline', color: 'teal', className: 'border-teal text-teal hover:bg-teal-bg' },
      { appearance: 'outline', color: 'blue', className: 'border-blue text-blue hover:bg-blue-bg' },
      { appearance: 'outline', color: 'mauve', className: 'border-mauve text-mauve hover:bg-mauve-bg' },
      { appearance: 'outline', color: 'slate', className: 'border-slate text-slate hover:bg-slate-bg' },
      { appearance: 'outline', color: 'lavender', className: 'border-lavender text-lavender hover:bg-lavender-bg' },
      { appearance: 'outline', color: 'sage', className: 'border-sage text-sage hover:bg-sage-bg' },
    ],
    defaultVariants: { appearance: 'filled', color: 'primary' },
  }
)

export interface TagProps
  extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'>,
    VariantProps<typeof tagVariants> {
  closable?: boolean
  onClose?: (event: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLButtonElement>) => void
  closeAriaLabel?: string
  closeIcon?: React.ReactNode
}

const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
  (
    {
      className,
      appearance = 'filled',
      color = 'primary',
      closable = false,
      onClose,
      closeAriaLabel = 'Close tag',
      closeIcon,
      children,
      onMouseEnter: onMouseEnterProp,
      onMouseLeave: onMouseLeaveProp,
      ...props
    },
    ref
  ) => {
    const [isHovered, setIsHovered] = React.useState(false)
    const [isCloseFocused, setIsCloseFocused] = React.useState(false)
    const showClose = closable && typeof onClose === 'function'
    const showCloseControl = isHovered || isCloseFocused

    const handleMouseEnter = (e: React.MouseEvent<HTMLSpanElement>) => {
      if (showClose) setIsHovered(true)
      onMouseEnterProp?.(e)
    }
    const handleMouseLeave = (e: React.MouseEvent<HTMLSpanElement>) => {
      if (showClose) setIsHovered(false)
      onMouseLeaveProp?.(e)
    }
    const handleCloseClick = (e: React.MouseEvent<HTMLButtonElement>) => {
      e.preventDefault()
      e.stopPropagation()
      onClose?.(e)
    }
    const handleCloseKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {
      if (e.key !== 'Enter' && e.key !== ' ') return
      e.preventDefault()
      e.stopPropagation()
      onClose?.(e)
    }

    return (
      <span
        ref={ref}
        className={cn(
          tagVariants({ appearance, color }),
          showClose && 'gap-0 pr-1.5',
          className
        )}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        {...props}
      >
        {children}
        {showClose && (
          <motion.div
            aria-hidden
            initial={false}
            animate={{
              width: showCloseControl ? 16 : 0,
              marginLeft: showCloseControl ? 2 : 0,
              opacity: showCloseControl ? 1 : 0,
            }}
            transition={{ duration: 0.2, ease: [0.4, 0, 0.2, 1] }}
            className="flex min-w-0 shrink-0 overflow-hidden"
            style={{ pointerEvents: showCloseControl ? 'auto' : 'none' }}
          >
            <button
              type="button"
              aria-label={closeAriaLabel}
              className="inline-flex h-4 w-4 cursor-pointer items-center justify-center rounded-sm text-current/80 hover:text-current focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-border"
              onClick={handleCloseClick}
              onKeyDown={handleCloseKeyDown}
              onFocus={() => setIsCloseFocused(true)}
              onBlur={() => setIsCloseFocused(false)}
            >
              {closeIcon ?? <CloseLargeLine className="h-3 w-3" />}
            </button>
          </motion.div>
        )}
      </span>
    )
  }
)
Tag.displayName = 'Tag'

export { Tag, tagVariants }
