import * as React from "react"
import { mergeProps } from "@base-ui/react/merge-props"
import { useRender } from "@base-ui/react/use-render"
import { cva, type VariantProps } from "class-variance-authority"
import { XIcon } from "lucide-react"

import { cn } from "@/lib/utils"

const badgeVariants = cva(
  "group/badge inline-flex w-fit shrink-0 items-center justify-center whitespace-nowrap rounded-full border font-medium outline-none transition-[background-color,border-color,color,box-shadow,opacity] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 [&>svg]:pointer-events-none [&>svg]:size-3.5 [&_[data-slot=badge-avatar]]:size-4 [&_[data-slot=badge-dot]]:size-1.5 [&_[data-slot=badge-dot]]:shrink-0 [&_[data-slot=badge-dot]]:rounded-full [&_[data-slot=badge-dot]]:bg-current [&_[data-slot=badge-dot][data-pulse=true]]:animate-pulse [&_[data-slot=badge-label]]:min-w-0 [&_[data-slot=badge-label]]:truncate [&_[data-slot=badge-remove]]:-mr-1 [&_[data-slot=badge-remove]]:inline-flex [&_[data-slot=badge-remove]]:size-4 [&_[data-slot=badge-remove]]:shrink-0 [&_[data-slot=badge-remove]]:items-center [&_[data-slot=badge-remove]]:justify-center [&_[data-slot=badge-remove]]:rounded-full [&_[data-slot=badge-remove]]:opacity-70 [&_[data-slot=badge-remove]]:transition-opacity hover:[&_[data-slot=badge-remove]]:opacity-100 focus-visible:[&_[data-slot=badge-remove]]:ring-2 focus-visible:[&_[data-slot=badge-remove]]:ring-ring [&_[data-icon=remove]]:size-3",
  {
    variants: {
      variant: {
        default: "border-transparent shadow-sm",
        secondary: "border-transparent bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
        destructive: "border-transparent bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
        soft: "border-transparent",
        outline: "bg-background shadow-sm",
        ghost: "border-transparent bg-transparent",
        link: "h-auto border-transparent bg-transparent p-0 text-primary underline-offset-4 hover:underline focus-visible:ring-0 focus-visible:ring-offset-0",
      },
      tone: {
        neutral: "",
        info: "",
        success: "",
        warning: "",
        danger: "",
        muted: "",
      },
      size: {
        sm: "h-5 gap-1 px-1.5 text-[10px] leading-none [&>svg]:size-3 [&_[data-slot=badge-avatar]]:size-3.5 [&_[data-slot=badge-dot]]:size-1.5",
        default: "h-6 gap-1.5 px-2.5 text-xs leading-none",
        lg: "h-7 gap-1.5 px-3 text-sm leading-none [&>svg]:size-4 [&_[data-slot=badge-avatar]]:size-5 [&_[data-slot=badge-dot]]:size-2",
      },
      dot: {
        true: "",
        false: "",
      },
    },
    compoundVariants: [
      {
        variant: "default",
        tone: "neutral",
        className: "bg-primary text-primary-foreground hover:bg-primary/90",
      },
      {
        variant: "default",
        tone: "info",
        className: "bg-blue-600 text-white hover:bg-blue-700",
      },
      {
        variant: "default",
        tone: "success",
        className: "bg-emerald-600 text-white hover:bg-emerald-700",
      },
      {
        variant: "default",
        tone: "warning",
        className: "bg-amber-500 text-white hover:bg-amber-600",
      },
      {
        variant: "default",
        tone: "danger",
        className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
      },
      {
        variant: "default",
        tone: "muted",
        className: "bg-muted text-muted-foreground hover:bg-muted/80",
      },
      {
        variant: "soft",
        tone: "neutral",
        className: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
      },
      {
        variant: "soft",
        tone: "info",
        className: "bg-blue-50 text-blue-700 hover:bg-blue-100 dark:bg-blue-950/60 dark:text-blue-300 dark:hover:bg-blue-950",
      },
      {
        variant: "soft",
        tone: "success",
        className: "bg-emerald-50 text-emerald-700 hover:bg-emerald-100 dark:bg-emerald-950/60 dark:text-emerald-300 dark:hover:bg-emerald-950",
      },
      {
        variant: "soft",
        tone: "warning",
        className: "bg-amber-50 text-amber-700 hover:bg-amber-100 dark:bg-amber-950/60 dark:text-amber-300 dark:hover:bg-amber-950",
      },
      {
        variant: "soft",
        tone: "danger",
        className: "bg-red-50 text-red-700 hover:bg-red-100 dark:bg-red-950/60 dark:text-red-300 dark:hover:bg-red-950",
      },
      {
        variant: "soft",
        tone: "muted",
        className: "bg-muted text-muted-foreground hover:bg-muted/80",
      },
      {
        variant: "outline",
        tone: "neutral",
        className: "border-border text-foreground hover:bg-accent hover:text-accent-foreground",
      },
      {
        variant: "outline",
        tone: "info",
        className: "border-blue-200 text-blue-700 hover:bg-blue-50 dark:border-blue-800 dark:text-blue-300 dark:hover:bg-blue-950/50",
      },
      {
        variant: "outline",
        tone: "success",
        className: "border-emerald-200 text-emerald-700 hover:bg-emerald-50 dark:border-emerald-800 dark:text-emerald-300 dark:hover:bg-emerald-950/50",
      },
      {
        variant: "outline",
        tone: "warning",
        className: "border-amber-200 text-amber-700 hover:bg-amber-50 dark:border-amber-800 dark:text-amber-300 dark:hover:bg-amber-950/50",
      },
      {
        variant: "outline",
        tone: "danger",
        className: "border-red-200 text-red-700 hover:bg-red-50 dark:border-red-800 dark:text-red-300 dark:hover:bg-red-950/50",
      },
      {
        variant: "outline",
        tone: "muted",
        className: "border-border text-muted-foreground hover:bg-muted",
      },
      {
        variant: "ghost",
        tone: "neutral",
        className: "text-foreground hover:bg-accent hover:text-accent-foreground",
      },
      {
        variant: "ghost",
        tone: "info",
        className: "text-blue-700 hover:bg-blue-50 dark:text-blue-300 dark:hover:bg-blue-950/50",
      },
      {
        variant: "ghost",
        tone: "success",
        className: "text-emerald-700 hover:bg-emerald-50 dark:text-emerald-300 dark:hover:bg-emerald-950/50",
      },
      {
        variant: "ghost",
        tone: "warning",
        className: "text-amber-700 hover:bg-amber-50 dark:text-amber-300 dark:hover:bg-amber-950/50",
      },
      {
        variant: "ghost",
        tone: "danger",
        className: "text-red-700 hover:bg-red-50 dark:text-red-300 dark:hover:bg-red-950/50",
      },
      {
        variant: "ghost",
        tone: "muted",
        className: "text-muted-foreground hover:bg-muted",
      },
    ],
    defaultVariants: {
      variant: "default",
      tone: "neutral",
      size: "default",
      dot: false,
    },
  }
)

type BadgeProps = useRender.ComponentProps<"span"> &
  Omit<VariantProps<typeof badgeVariants>, "dot"> & {
    label?: React.ReactNode
    count?: React.ReactNode
    status?: "neutral" | "info" | "success" | "warning" | "danger" | "muted"
    removable?: boolean
    selected?: boolean
    onRemove?: () => void
    removeLabel?: string
    leftIcon?: React.ReactNode
    rightIcon?: React.ReactNode
    avatar?: React.ReactNode
    dot?: boolean | React.ReactNode
    showDot?: boolean
    dotPosition?: "start" | "end"
    pulse?: boolean
    interactive?: boolean
  }

function Badge({
  className,
  variant = "default",
  tone = "neutral",
  size = "default",
  dot = false,
  label,
  count,
  status,
  removable = false,
  selected = false,
  onRemove,
  removeLabel = "Remove badge",
  leftIcon,
  rightIcon,
  avatar,
  showDot,
  dotPosition = "start",
  pulse = false,
  interactive = false,
  children,
  render,
  onKeyDown,
  ...props
}: BadgeProps) {
  const resolvedTone = status ?? tone
  const resolvedLabel = label ?? children
  const resolvedShowDot = showDot ?? Boolean(dot || status === "success" || status === "warning" || status === "danger" || status === "info")
  const dotNode = resolvedShowDot ? (
    <span data-slot="badge-dot" data-pulse={pulse || undefined}>
      {React.isValidElement(dot) ? dot : null}
    </span>
  ) : null

  return useRender({
    defaultTagName: "span",
    props: mergeProps<"span">(
      {
        className: cn(
          badgeVariants({ variant, tone: resolvedTone, size, dot: resolvedShowDot }),
          selected && "ring-2 ring-ring/45 ring-offset-1",
          interactive && "cursor-pointer",
          className
        ),
        tabIndex: removable || interactive ? 0 : undefined,
        onKeyDown: (event: React.KeyboardEvent<HTMLSpanElement>) => {
          if (removable && (event.key === "Backspace" || event.key === "Delete")) {
            event.preventDefault()
            onRemove?.()
          }
          onKeyDown?.(event)
        },
        children: (
          <>
            {dotPosition === "start" ? dotNode : null}
            {avatar ? <span data-slot="badge-avatar" className="grid shrink-0 place-items-center overflow-hidden rounded-full">{avatar}</span> : null}
            {leftIcon ? <span data-icon="inline-start" data-slot="badge-icon" className="grid shrink-0 place-items-center">{leftIcon}</span> : null}
            {resolvedLabel ? <span data-slot="badge-label">{resolvedLabel}</span> : null}
            {count != null ? (
              <span
                data-slot="badge-count"
              >
                {count}
              </span>
            ) : null}
            {rightIcon ? <span data-icon="inline-end" data-slot="badge-icon" className="grid shrink-0 place-items-center">{rightIcon}</span> : null}
            {dotPosition === "end" ? dotNode : null}
            {removable ? (
              <button
                type="button"
                data-slot="badge-remove"
                aria-label={removeLabel}
                onClick={(event) => {
                  event.preventDefault()
                  event.stopPropagation()
                  onRemove?.()
                }}
              >
                <XIcon data-icon="remove" />
              </button>
            ) : null}
          </>
        ),
      } as React.HTMLAttributes<HTMLSpanElement>,
      {
        "data-variant": variant ?? "default",
        "data-tone": resolvedTone ?? "neutral",
        "data-size": size ?? "default",
        "data-removable": removable || undefined,
        "data-selected": selected || undefined,
        "data-interactive": interactive || undefined,
        "data-pulse": pulse || undefined,
      } as React.HTMLAttributes<HTMLSpanElement>,
      props
    ),
    render,
    state: {
      slot: "badge",
      variant,
      tone: resolvedTone,
      size,
      dot: resolvedShowDot,
    },
  })
}

export { Badge, badgeVariants, type BadgeProps }
