import { isTerminal } from '@/hooks/useBatchPolling'
import { formatNumber } from '@/lib/format'
import { t } from '@/lib/i18n'
import { cn } from '@/lib/utils'

/**
 * Las fallidas se dibujan con rayas y no sólo con otro color: en escala de
 * grises un tramo liso más oscuro se lee como «un poco más de avance», que es
 * lo contrario de lo que pasó (RT-04).
 */
const FAILED_STRIPES =
  'repeating-linear-gradient(45deg, var(--destructive) 0 3px, color-mix(in oklab, var(--destructive) 30%, transparent) 3px 6px)'

/**
 * Hasta dónde puede llegar la barra de un lote que no dice «Completado».
 *
 * Las cifras no siempre dejan hueco. Una sincronización que lee los siete
 * sitemaps y no consigue cupo para enviar uno cierra en `PARTIAL` con
 * `processed == total` y `failed == 0`, porque la nota de cupo no incrementa
 * ninguna de las dos cifras. Calculada tal cual, la barra queda llena, sólida,
 * sin rayas y sin hueco: idéntica a la de un lote terminado, y lo único que las
 * separa pasa a ser el color del badge, que es exactamente lo que R-C prohíbe.
 *
 * El tope deja siempre un resto visible. No es una mentira al revés —la cifra
 * exacta está escrita debajo, en palabras y en números—: es que la barra
 * afirmaría «se procesaron todas» sobre un lote que no terminó.
 */
const MAX_INCOMPLETE_RATIO = 0.94

interface Props {
  total: number
  processed: number
  failed: number
  state: string
  className?: string
}

/**
 * Avance real de un lote (C-17, RT-13).
 *
 * El avance se calcula desde las cifras; del estado sale una sola cosa, que es
 * el tope. Un lote `PARTIAL` terminó, pero **no** llegó al final: con
 * `processed < total` la barra no toca el borde por aritmética, y cuando las
 * cifras no dejan hueco —leyó los siete sitemaps y no consiguió cupo para
 * enviar uno— la deja corta `MAX_INCOMPLETE_RATIO`. Una barra llena dice «se
 * consultaron todas» y eso sería falso justo en el caso que más importa (R-C),
 * así que sólo «Completado» llega al borde.
 *
 * En cola no hay animación de ningún tipo. Una barra indeterminada reptando en
 * un lote que todavía no arrancó inventa un avance que no existe (RT-14).
 */
export function BatchProgress({ total, processed, failed, state, className }: Props) {
  const safeTotal = Math.max(total, 0)
  const safeProcessed = Math.min(Math.max(processed, 0), safeTotal)
  const safeFailed = Math.min(Math.max(failed, 0), Math.max(safeTotal - safeProcessed, 0))
  const attended = safeProcessed + safeFailed
  const pending = Math.max(safeTotal - attended, 0)

  const queued = state === 'QUEUED'
  const terminal = isTerminal(state)
  const completed = state === 'COMPLETED'
  // Terminó y no dice «Completado»: quedó algo sin hacer, lo muestren las
  // cifras o no.
  const incomplete = terminal && !completed
  const ratio = (value: number) => {
    if (safeTotal <= 0) return 0
    const exact = value / safeTotal
    return completed ? exact : Math.min(exact, MAX_INCOMPLETE_RATIO)
  }

  const countText = t('batchProgress.count', {
    processed: formatNumber(safeProcessed),
    total: formatNumber(safeTotal),
  })
  // El hueco de la barra no lo anuncia un lector de pantalla: lo que se anuncia
  // es esto, así que la incompletitud tiene que estar acá también (RT-04).
  const valueText = queued
    ? t('batchProgress.notStarted')
    : incomplete
      ? t('batchProgress.valueIncomplete', { count: countText })
      : countText

  if (safeTotal === 0) {
    // «No tenía ítems» es una conclusión, y sólo se puede sacar cuando el lote
    // cerró **bien**. Dicha sobre uno que todavía está corriendo afirma un
    // resultado que nadie tiene, y dicha sobre uno que falló antes de contar
    // nada —el dominio perdió el acceso entre el clic y la ejecución— se lee
    // como éxito justo debajo del badge que dice «Falló».
    return (
      <p className={cn('text-muted-foreground text-sm', className)}>
        {queued
          ? t('batchProgress.empty.queued')
          : completed
            ? t('batchProgress.empty.completed')
            : terminal
              ? t('batchProgress.empty.terminal')
              : t('batchProgress.empty.unknown')}
      </p>
    )
  }

  return (
    <div className={cn('flex flex-col gap-1.5', className)}>
      <div
        role="progressbar"
        aria-label={t('batchProgress.label')}
        aria-valuemin={0}
        aria-valuemax={safeTotal}
        aria-valuenow={safeProcessed}
        aria-valuetext={valueText}
        className="bg-muted relative h-1.5 w-full overflow-hidden rounded-full"
      >
        {/* Primero el tramo atendido —procesadas más fallidas— y encima el
            procesado: así el sobrante rayado que queda a la vista es
            exactamente lo que falló. */}
        <span
          aria-hidden
          className="absolute inset-0 origin-left transition-transform duration-300 ease-out motion-reduce:transition-none"
          style={{ transform: `scaleX(${ratio(attended)})`, backgroundImage: FAILED_STRIPES }}
        />
        <span
          aria-hidden
          className="bg-primary absolute inset-0 origin-left transition-transform duration-300 ease-out motion-reduce:transition-none"
          style={{ transform: `scaleX(${ratio(safeProcessed)})` }}
        />
      </div>

      <p className="text-sm tabular-nums">
        {queued ? (
          <span className="text-muted-foreground">
            {t('batchProgress.queued', { total: formatNumber(safeTotal) })}
          </span>
        ) : (
          countText
        )}
        {safeFailed > 0 ? (
          <span className="text-destructive">
            {' '}
            · {t('batchProgress.failed', { count: safeFailed, total: formatNumber(safeFailed) })}
          </span>
        ) : null}
      </p>

      {/*
        Cuando las cifras dejan hueco, el hueco ya lo dice. Cuando no lo dejan
        —el lote leyó todo y se quedó sin cupo para enviar— la incompletitud
        sólo existe si está escrita: el tope de la barra son unos píxeles que en
        escala de grises no se leen, y el badge es color. Acá no va **por qué**
        quedó incompleto: eso lo escribe `batchReasonText`, que en las dos
        pantallas está al lado de esta barra.
      */}
      {terminal && pending > 0 ? (
        <p className="text-muted-foreground text-xs tabular-nums">
          {t('batchProgress.pending', { count: pending, total: formatNumber(pending) })}
        </p>
      ) : incomplete ? (
        <p className="text-muted-foreground text-xs">{t('batchProgress.incomplete')}</p>
      ) : null}
    </div>
  )
}
