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

import { cn } from './utils'

const badgeVariants = cva(
  'inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-[10px] font-semibold tracking-wide tabular-nums w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none transition-all duration-200 overflow-hidden',
  {
    variants: {
      variant: {
        default: 'border-transparent bg-primary text-primary-foreground',
        secondary: 'border-transparent bg-foreground/[0.08] text-foreground-secondary',
        destructive: 'border-transparent bg-rose-10 text-[var(--color-error-text)]',
        outline:
          'border-border-default/50 bg-transparent text-foreground [a&]:hover:bg-foreground/[0.07]',
        glass: 'border-transparent bg-foreground/[0.08] text-foreground-secondary',
        orange: 'border-transparent bg-primary/15 text-[var(--color-primary-text)]',
        blue: 'border-transparent bg-blue-10 text-[var(--color-blue-text)]',
        cyan: 'border-transparent bg-cyan-10 text-[var(--color-cyan-text)]',
        emerald: 'border-transparent bg-emerald-10 text-[var(--color-emerald-text)]',
        rose: 'border-transparent bg-rose-10 text-[var(--color-rose-text)]',
        amber: 'border-transparent bg-amber-10 text-[var(--color-amber-text)]',
        violet: 'border-transparent bg-violet-10 text-[var(--color-violet-text)]',
        live: 'border-transparent bg-cyan-10 text-[var(--color-cyan-text)]',
      },
    },
    defaultVariants: {
      variant: 'default',
    },
  }
)

export type BadgeSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info'
export type BadgeStatus = 'active' | 'inactive' | 'pending' | 'error'

export type BadgeProps = React.ComponentProps<'span'> &
  VariantProps<typeof badgeVariants> & {
    asChild?: boolean
    /** When true, renders a small color dot before children. */
    dot?: boolean
    /** When provided, renders a trailing × close button that calls this callback. */
    onRemove?: () => void
    /**
     * Severity preset — overrides `variant`.
     * critical → rose, high → orange, medium → amber, low → cyan, info → glass.
     * When both `severity` and `status` are set, `severity` wins.
     */
    severity?: BadgeSeverity
    /**
     * Status preset — overrides `variant` and forces `dot=true`.
     * active → emerald+dot, inactive → glass, pending → amber+dot, error → rose+dot.
     */
    status?: BadgeStatus
  }

/** Map severity preset → CVA variant key */
const SEVERITY_VARIANT: Record<BadgeSeverity, VariantProps<typeof badgeVariants>['variant']> = {
  critical: 'rose',
  high: 'orange',
  medium: 'amber',
  low: 'cyan',
  info: 'glass',
}

/** Map status preset → CVA variant key */
const STATUS_VARIANT: Record<BadgeStatus, VariantProps<typeof badgeVariants>['variant']> = {
  active: 'emerald',
  inactive: 'glass',
  pending: 'amber',
  error: 'rose',
}

/** Statuses that force the dot indicator */
const STATUS_FORCES_DOT = new Set<BadgeStatus>(['active', 'pending', 'error'])

let _warnedBothPresets = false

function Badge({
  className,
  variant,
  asChild = false,
  dot,
  onRemove,
  severity,
  status,
  children,
  ...props
}: BadgeProps) {
  // Warn once in dev when both severity and status are provided
  if (severity !== undefined && status !== undefined) {
    if (process.env.NODE_ENV !== 'production' && !_warnedBothPresets) {
      _warnedBothPresets = true
      console.warn(
        '[Badge] Both `severity` and `status` props were provided. `severity` takes precedence.'
      )
    }
  }

  // Resolve effective CVA variant
  let effectiveVariant: VariantProps<typeof badgeVariants>['variant'] = variant
  let effectiveDot = dot

  if (severity !== undefined) {
    effectiveVariant = SEVERITY_VARIANT[severity]
  } else if (status !== undefined) {
    effectiveVariant = STATUS_VARIANT[status]
    // Status presets force dot unless caller explicitly set dot=false
    if (dot === undefined && STATUS_FORCES_DOT.has(status)) {
      effectiveDot = true
    }
  }

  const Comp = asChild ? Slot : 'span'

  // Warn in dev when onRemove is used with asChild (Slot can't append extra children safely)
  if (asChild && onRemove !== undefined && process.env.NODE_ENV !== 'production') {
    console.warn(
      '[Badge] `onRemove` is ignored when `asChild` is true — Slot must wrap a single child element.'
    )
  }

  const handleRemove = (e: React.MouseEvent<HTMLButtonElement>) => {
    e.stopPropagation()
    onRemove?.()
  }

  const sharedProps = {
    'data-slot': 'badge' as const,
    'data-severity': severity,
    'data-status': status,
    className: cn(badgeVariants({ variant: effectiveVariant }), className),
    ...props,
  }

  if (asChild) {
    // Slot requires exactly one child element — pass children through directly.
    return <Comp {...sharedProps}>{children}</Comp>
  }

  return (
    <Comp {...sharedProps}>
      {effectiveDot ? <span aria-hidden className="size-1.5 rounded-full bg-current" /> : null}
      {children}
      {onRemove !== undefined ? (
        <button
          type="button"
          aria-label="Remove"
          onClick={handleRemove}
          className="size-3 text-current opacity-60 hover:opacity-100 flex items-center justify-center"
        >
          ×
        </button>
      ) : null}
    </Comp>
  )
}

export function severityBadge(
  severity: BadgeSeverity,
  props?: Omit<BadgeProps, 'severity'>
): BadgeProps {
  return { ...props, severity }
}

export function statusBadge(status: BadgeStatus, props?: Omit<BadgeProps, 'status'>): BadgeProps {
  return { ...props, status }
}

export { Badge, badgeVariants }
