import type { ReactNode } from 'react'

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

export interface LabelValueProps {
  term: string
  value: ReactNode
  /** La aclaración corta debajo del valor, cuando el término no alcanza. */
  hint?: string
  /**
   * Hacia dónde se alinea el par. Por omisión, al inicio.
   *
   * Reemplaza a `numeric`, que decía **qué era el dato** y de ahí deducía un
   * layout: quien la marcaba estaba pensando «esto es un número», no «quiero
   * esto contra el margen derecho», y terminaba pidiendo sin saberlo una
   * alineación que casi nunca era la que la pantalla necesitaba. Alinear a la
   * derecha sirve en una columna de tabla, donde las unidades caen bajo las
   * unidades; en una lista de descripción de dos columnas deja el término a la
   * izquierda, el valor a la derecha y un hueco en el medio que hay que cruzar
   * con la vista para aparearlos.
   *
   * Ahora la prop dice sólo lo que hace, así que pedirla es una decisión de
   * quien dibuja la pantalla y no una consecuencia del tipo de dato.
   */
  align?: 'start' | 'end'
}

/**
 * Un par etiqueta/valor suelto.
 *
 * Las fichas de dominio, de lote y de credencial son todas esto, y estaban
 * dibujadas a mano en cada una con su propio tamaño y su propio hueco. Acá el
 * par tiene una sola anatomía: `dt` en T6 muted, `dd` en T5, 4 px entre los dos.
 *
 * **Un par nunca es una tarjeta y nunca lleva borde propio.** El borde es de la
 * `Card` o de la `Section` que contiene al grupo entero; dárselo a cada par es
 * lo que convierte una ficha de seis datos en seis cajas.
 *
 * `wrap-anywhere` en el valor porque la mitad de estos valores son URLs y
 * hostnames: sin eso, uno largo empuja la página entera.
 */
export function LabelValue({ term, value, hint, align = 'start' }: LabelValueProps) {
  return (
    <div className={cn('flex min-w-0 flex-col gap-1', align === 'end' && 'items-end')}>
      <dt className="text-muted-foreground text-xs">{term}</dt>
      <dd className={cn('min-w-0 wrap-anywhere', align === 'end' && 'text-right')}>
        {value}
        {hint ? (
          <span className="text-muted-foreground block text-xs text-pretty">{hint}</span>
        ) : null}
      </dd>
    </div>
  )
}

interface DescriptionListProps {
  items: LabelValueProps[]
  columns?: 1 | 2
  className?: string
}

/**
 * Un grupo de pares de sólo lectura, en una `<dl>` de verdad.
 *
 * Que sea una lista de descripción y no una pila de `<div>` es lo que hace que
 * un lector de pantalla anuncie «6 elementos» y pueda saltar de término en
 * término, en vez de leer doce líneas sueltas sin relación entre sí.
 *
 * Si el grupo pasa de ocho pares, la mitad se va a un `Sheet` o a una pestaña:
 * la ficha no se agranda. Y si un par necesita una acción al lado, deja de ser
 * un par y pasa a ser un `Item`.
 */
export function DescriptionList({ items, columns = 1, className }: DescriptionListProps) {
  return (
    <dl
      className={cn(
        'grid grid-cols-1 gap-3',
        columns === 2 && 'md:grid-cols-2 md:gap-x-8',
        className
      )}
    >
      {items.map((item) => (
        <LabelValue key={item.term} {...item} />
      ))}
    </dl>
  )
}
