import * as React from 'react'
import { cva, type VariantProps } from 'class-variance-authority'

import { cn } from './utils'

/* ------------------------------------------------------------------ */
/*  Avatar                                                             */
/* ------------------------------------------------------------------ */

const avatarVariants = cva(
  'relative inline-flex shrink-0 items-center justify-center overflow-hidden bg-glass border border-border-glass',
  {
    variants: {
      size: {
        xs: 'size-6 text-[10px]',
        sm: 'size-8 text-xs',
        md: 'size-10 text-sm',
        lg: 'size-12 text-base',
        xl: 'size-16 text-lg',
      },
      shape: {
        circle: 'rounded-full',
        square: 'rounded-xl',
      },
    },
    defaultVariants: {
      size: 'md',
      shape: 'circle',
    },
  }
)

type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
type AvatarShape = 'circle' | 'square'
type AvatarStatus = 'online' | 'offline' | 'away' | 'busy'

export type AvatarProps = React.ComponentProps<'div'> &
  VariantProps<typeof avatarVariants> & {
    status?: AvatarStatus
  }

function Avatar({ className, size, shape, status, children, ...props }: AvatarProps) {
  return (
    <div
      data-slot="avatar"
      role="img"
      className={cn(avatarVariants({ size, shape }), className)}
      {...props}
    >
      {children}
      {status && <AvatarStatusIndicator status={status} />}
    </div>
  )
}

/* ------------------------------------------------------------------ */
/*  AvatarImage                                                        */
/* ------------------------------------------------------------------ */

export type AvatarImageProps = React.ComponentProps<'img'> & {
  onLoadingStatusChange?: (status: 'loading' | 'loaded' | 'error') => void
}

function AvatarImage({
  className,
  src,
  alt = '',
  onLoadingStatusChange,
  ...props
}: AvatarImageProps) {
  const [status, setStatus] = React.useState<'loading' | 'loaded' | 'error'>('loading')

  React.useEffect(() => {
    setStatus('loading')
  }, [src])

  if (status === 'error') {
    return null
  }

  return (
    <img
      data-slot="avatar-image"
      src={src}
      alt={alt}
      className={cn('aspect-square size-full object-cover', className)}
      onLoad={() => {
        setStatus('loaded')
        onLoadingStatusChange?.('loaded')
      }}
      onError={() => {
        setStatus('error')
        onLoadingStatusChange?.('error')
      }}
      {...props}
    />
  )
}

/* ------------------------------------------------------------------ */
/*  AvatarFallback                                                     */
/* ------------------------------------------------------------------ */

function AvatarFallback({ className, ...props }: React.ComponentProps<'span'>) {
  return (
    <span
      data-slot="avatar-fallback"
      className={cn(
        'flex size-full items-center justify-center font-semibold text-foreground-secondary',
        className
      )}
      {...props}
    />
  )
}

/* ------------------------------------------------------------------ */
/*  AvatarStatusIndicator (internal)                                   */
/* ------------------------------------------------------------------ */

const statusColors: Record<AvatarStatus, string> = {
  online: 'bg-accent-emerald',
  offline: 'bg-foreground-muted',
  away: 'bg-accent-amber',
  busy: 'bg-accent-rose',
}

function AvatarStatusIndicator({ status }: { status: AvatarStatus }) {
  return (
    <span
      aria-hidden="true"
      className={cn(
        'absolute bottom-0 right-0 block size-2.5 rounded-full ring-2 ring-background',
        statusColors[status]
      )}
    />
  )
}

/* ------------------------------------------------------------------ */
/*  AvatarGroup                                                        */
/* ------------------------------------------------------------------ */

export interface AvatarGroupProps extends React.ComponentProps<'div'> {
  /** Maximum number of avatars to show before truncating */
  max?: number
}

function AvatarGroup({ className, max, children, ...props }: AvatarGroupProps) {
  const childArray = React.Children.toArray(children)
  const total = childArray.length
  const limit = max !== undefined && max < total ? max : total
  const overflow = total - limit
  const visibleChildren = childArray.slice(0, limit)

  return (
    <div
      data-slot="avatar-group"
      role="group"
      aria-label="Avatar group"
      className={cn('flex -space-x-2', className)}
      {...props}
    >
      {visibleChildren.map((child, index) => (
        <div key={index} className="ring-2 ring-background rounded-full">
          {child}
        </div>
      ))}
      {overflow > 0 && (
        <span
          aria-label={`${overflow} more`}
          className="inline-flex size-10 items-center justify-center rounded-full border border-border-glass bg-glass text-xs font-semibold text-foreground-secondary ring-2 ring-background backdrop-blur-[20px]"
        >
          +{overflow}
        </span>
      )}
    </div>
  )
}

export {
  Avatar,
  AvatarImage,
  AvatarFallback,
  AvatarGroup,
  avatarVariants,
  type AvatarSize,
  type AvatarShape,
  type AvatarStatus,
}
