import { ArrowRight, ChevronRight } from 'lucide-react'
import type { ReactNode } from 'react'

import { CodeChip } from '@/components/CodeChip'
import { CoverageStateBadge } from '@/components/CoverageStateBadge'
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from '@/components/ui/collapsible'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/dialog'
import { formatNumber } from '@/lib/format'
import { t } from '@/lib/i18n'

/**
 * Una lista de direcciones, en un modal, sin salir de la pantalla.
 *
 * Existe porque la ficha del lote no tenía manera de mostrar una lista: todo lo
 * que era lista se volvía un enlace, y el enlace apuntaba a la tabla de
 * cobertura —la única pantalla que existía— aunque contestara **otra pregunta**.
 * «Doce quedaron rastreadas y sin indexar» es un hecho de ese recorrido; la
 * tabla muestra cuáles están así hoy, después de que los recorridos siguientes
 * pisaran el estado. Las dos listas casi nunca coinciden, y la de la tabla
 * llegaba sin nada que explicara la diferencia.
 *
 * La regla que deja: **una cifra se abre donde se la lee**. Mandar a otra
 * pantalla se reserva para cuando el destino contesta la misma pregunta.
 */
export function UrlListDialog({
  trigger,
  title,
  description,
  before,
  after,
  fetchedAt,
  urls,
  total,
}: {
  /** Lo que se pulsa. Va como `asChild`, así que tiene que aceptar un ref. */
  trigger: ReactNode
  title: string
  description: string
  /** Estado de partida. Sin él no hay movimiento que mostrar, sólo un estado. */
  before?: string
  after?: string
  /**
   * Cuándo lo dijo Google. `CoverageStateBadge` la trata como obligatoria y sin
   * ella pinta el estado como defecto: acá existe —es la del lote—, así que se
   * pasa y el badge sale con el color que le corresponde.
   */
  fetchedAt?: string | null
  urls: string[]
  /** El total real. Puede ser mayor que `urls`, que viene recortada. */
  total: number
}) {
  const hidden = Math.max(total - urls.length, 0)

  return (
    <Dialog>
      <DialogTrigger asChild>{trigger}</DialogTrigger>
      <DialogContent className="sm:max-w-xl">
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
          <DialogDescription>{description}</DialogDescription>
        </DialogHeader>

        {after ? (
          <States before={before} after={after} fetchedAt={fetchedAt ?? null} />
        ) : null}

        {urls.length === 0 ? (
          // Un lote que todavía corre, o uno anterior a que esto se guardara.
          // Decirlo es más honesto que mostrar una lista vacía debajo de una
          // cifra que dice que hay algo.
          <p className="text-muted-foreground text-sm text-pretty">{t('urlList.unavailable')}</p>
        ) : (
          /* Plegadas: el modal ya contesta «qué pasó» con los estados de arriba,
             y «sobre cuáles» es el paso siguiente. Una lista larga abierta de
             entrada empuja fuera de la vista lo que da sentido a leerla. */
          <Collapsible>
            <CollapsibleTrigger className="focus-visible:ring-ring group flex items-center gap-1.5 rounded text-sm focus-visible:ring-2 focus-visible:outline-none">
              <ChevronRight
                className="size-4 transition-transform group-data-[state=open]:rotate-90 motion-reduce:transition-none"
                aria-hidden
              />
              {t('urlList.addresses', { count: total, total: formatNumber(total) })}
            </CollapsibleTrigger>

            <CollapsibleContent className="max-h-80 space-y-1 overflow-y-auto pt-2">
              {urls.map((loc) => (
                <CodeChip key={loc} value={loc} copy />
              ))}

              {hidden > 0 ? (
                <p className="text-muted-foreground pt-1 text-sm text-pretty">
                  {t('urlList.truncated', { count: hidden, total: formatNumber(hidden) })}
                </p>
              ) : null}
            </CollapsibleContent>
          </Collapsible>
        )}
      </DialogContent>
    </Dialog>
  )
}

/**
 * De qué estado a cuál, o el estado solo.
 *
 * La rejilla es `1fr auto 1fr` y no se dibuja: lo que alinea son los dos badges
 * contra la flecha del medio. Un contenedor con borde acá sería una caja dentro
 * de la caja del modal, que es la que ya encierra todo esto.
 */
function States({
  before,
  after,
  fetchedAt,
}: {
  before?: string
  after: string
  fetchedAt: string | null
}) {
  if (!before) {
    return (
      <div className="flex justify-center">
        <CoverageStateBadge state={after} fetchedAt={fetchedAt} />
      </div>
    )
  }

  return (
    <div className="grid grid-cols-[1fr_auto_1fr] items-center gap-3">
      <Side label={t('urlList.before')} state={before} fetchedAt={fetchedAt} />
      <ArrowRight className="text-muted-foreground size-4 self-end pb-1.5" aria-hidden />
      <Side label={t('urlList.after')} state={after} fetchedAt={fetchedAt} />
    </div>
  )
}

function Side({
  label,
  state,
  fetchedAt,
}: {
  label: string
  state: string
  fetchedAt: string | null
}) {
  return (
    <div className="flex flex-col items-center gap-1.5">
      <span className="text-muted-foreground text-xs">{label}</span>
      <CoverageStateBadge state={state} fetchedAt={fetchedAt} />
    </div>
  )
}
