import { Check } from 'lucide-react'
import { RadioGroup as RadioGroupPrimitive } from 'radix-ui'
import type { ComponentType, SVGProps } from 'react'

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

/** Un botón: su valor, cómo se dice y su ícono, ya resueltos por quien llama. */
export interface ChoiceItem {
  value: string
  label: string
  description?: string
  icon: ComponentType<SVGProps<SVGSVGElement>> | null
}

interface Props {
  /** Las opciones vigentes, en el orden del catálogo. Dos o tres. */
  items: ChoiceItem[]
  value: string
  onChange: (value: string) => void
  /** El id del grupo: es adonde salta el foco cuando falta contestar. */
  id: string
  /** Ids del rótulo y del error, para que el grupo se nombre y se explique. */
  labelledBy: string
  describedBy?: string
  invalid?: boolean
}

/**
 * Pocas opciones que se leen como un interruptor: botones grandes lado a lado,
 * y al prender uno se apaga el otro.
 *
 * Es un grupo de radios y no dos botones sueltos, por lo mismo que las
 * tarjetas con foto: se elige una entre varias, y las flechas del teclado lo
 * recorren como cualquier radio. La diferencia con esas tarjetas es el peso:
 * acá no hay foto que mirar, la decisión es una sola palabra, y lo que la hace
 * legible de un vistazo es el ícono.
 *
 * La elegida se marca tres veces —borde, ícono invertido y tilde— porque con
 * dos botones iguales una sola señal deja dudando cuál está prendido.
 */
export function SegmentedChoice({
  items,
  value,
  onChange,
  id,
  labelledBy,
  describedBy,
  invalid,
}: Props) {
  return (
    <RadioGroupPrimitive.Root
      id={id}
      tabIndex={-1}
      value={value}
      onValueChange={onChange}
      aria-labelledby={labelledBy}
      aria-describedby={describedBy}
      aria-invalid={invalid || undefined}
      // Tantas columnas como opciones, y no más anchas que lo que se lee: dos
      // botones estirados de lado a lado de la tarjeta separan el ícono de su
      // tilde por media pantalla.
      className="grid gap-3 sm:max-w-xl"
      style={{ gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` }}
    >
      {items.map((item) => {
        const Icon = item.icon
        return (
          <RadioGroupPrimitive.Item
            key={item.value}
            value={item.value}
            className={cn(
              'bg-card text-card-foreground group/choice relative flex flex-col items-start gap-3 rounded-lg border p-3 text-left transition-colors',
              // En el teléfono el ícono va arriba del texto: lado a lado no
              // entran dos en el ancho, y el rótulo se partiría.
              'sm:flex-row sm:items-center sm:gap-4 sm:p-4 sm:pr-12',
              'hover:border-foreground/40 focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none',
              'data-[state=checked]:border-foreground data-[state=checked]:bg-muted/40',
              invalid && 'border-destructive'
            )}
          >
            {Icon ? (
              <span
                className={cn(
                  'bg-muted text-muted-foreground flex size-12 shrink-0 items-center justify-center rounded-md transition-colors',
                  'group-data-[state=checked]/choice:bg-foreground group-data-[state=checked]/choice:text-background'
                )}
              >
                <Icon className="size-7" />
              </span>
            ) : null}
            <span className="flex min-w-0 flex-col gap-0.5 pr-6 sm:pr-0">
              <span className="font-medium">{item.label}</span>
              {item.description ? (
                <span className="text-muted-foreground text-xs">{item.description}</span>
              ) : null}
            </span>
            <span
              aria-hidden
              className={cn(
                'absolute top-3 right-3 flex size-5 items-center justify-center rounded-full border transition-colors sm:top-1/2 sm:right-4 sm:-translate-y-1/2',
                'group-data-[state=checked]/choice:border-foreground group-data-[state=checked]/choice:bg-foreground group-data-[state=checked]/choice:text-background'
              )}
            >
              <Check className="size-3 opacity-0 transition-opacity group-data-[state=checked]/choice:opacity-100" />
            </span>
          </RadioGroupPrimitive.Item>
        )
      })}
    </RadioGroupPrimitive.Root>
  )
}
