import {
  CircleAlert,
  CircleCheck,
  CircleEllipsis,
  CircleSlash,
  Clock,
  Copy,
  EyeOff,
  Search,
  ShieldBan,
  CornerUpRight,
} from 'lucide-react'
import type { LucideIcon } from 'lucide-react'

import { DataTimestamp } from '@/components/DataTimestamp'
import { StatusBadge } from '@/components/StatusBadge'
import type { StatusTone } from '@/components/StatusBadge'
import { t } from '@/lib/i18n'
import type { TranslationKey } from '@/lib/i18n'

/**
 * Tres familias visuales, nunca dos: **con dato positivo**, **con dato
 * negativo** y **sin dato** (RT-03).
 *
 * `UNKNOWN` no es un estado negativo: significa que todavía no le preguntamos a
 * Google. Pintarlo de rojo o de ámbar lo agruparía con las que sí están sin
 * indexar, y eso es afirmar algo que nadie comprobó. Va con borde punteado,
 * fondo neutro y un reloj — ni verde, ni rojo, ni ámbar.
 */
type Family = 'positive' | 'negative' | 'no-data'

/**
 * Los diez estados, con lo único que no depende del idioma: su icono y su
 * familia.
 *
 * La palabra y su ayuda están en el catálogo, bajo `coverage.<ESTADO>.label` y
 * `.help`. Este mapa se arma al importar el módulo, que es antes de que el
 * catálogo exista.
 */
const STATES: Record<string, { icon: LucideIcon; family: Family }> = {
  UNKNOWN: {
    icon: Clock,
    family: 'no-data',
  },
  INDEXED: {
    icon: CircleCheck,
    family: 'positive',
  },
  CRAWLED_NOT_INDEXED: {
    icon: Search,
    family: 'negative',
  },
  DISCOVERED_NOT_INDEXED: {
    icon: CircleSlash,
    family: 'negative',
  },
  DUPLICATE_CANONICAL: {
    icon: Copy,
    family: 'negative',
  },
  EXCLUDED_NOINDEX: {
    icon: EyeOff,
    family: 'negative',
  },
  BLOCKED_ROBOTS: {
    icon: ShieldBan,
    family: 'negative',
  },
  FETCH_ERROR: {
    icon: CircleAlert,
    family: 'negative',
  },
  REDIRECT: {
    icon: CornerUpRight,
    family: 'negative',
  },
  OTHER_NOT_INDEXED: {
    // Icono propio y no el de `FETCH_ERROR`: los diez estados tienen que
    // distinguirse en escala de grises, así que dos de ellos no pueden
    // compartir dibujo y confiar en que el color los separe (RT-04).
    icon: CircleEllipsis,
    family: 'negative',
  },
}

/**
 * Las tres familias, dichas en el juego de tonos de `StatusBadge`.
 *
 * La correspondencia es la única decisión que se toma acá: el dibujo —qué verde,
 * qué ámbar, qué punteado— dejó de vivir en este archivo para que los tres
 * badges del producto tengan una sola forma. Lo que sigue siendo de acá es a qué
 * familia pertenece cada uno de los diez estados, que es el conocimiento del
 * dominio.
 */
const TONE: Record<Family, StatusTone> = {
  positive: 'positive',
  negative: 'attention',
  'no-data': 'unknown',
}

interface Props {
  state: string
  /** Fecha en que Google devolvió el dato. Obligatoria salvo en «sin consultar». */
  fetchedAt: string | null
}

/**
 * El par estado + fecha, que no se puede separar (RT-02).
 *
 * Un estado con dato y sin fecha de obtención se muestra como defecto y no se
 * disimula: no sabemos de cuándo es el dato, y ocultarlo o inventarle una fecha
 * sería exactamente la clase de afirmación que este producto no puede hacer.
 */
export function CoverageStateBadge({ state, fetchedAt }: Props) {
  const known = STATES[state] ? state : 'OTHER_NOT_INDEXED'
  const definition = STATES[known]
  const missingDate = state !== 'UNKNOWN' && !fetchedAt

  return (
    <StatusBadge
      // El defecto se dice con el tono, pero el icono sigue siendo el del estado:
      // la URL tiene el estado que tiene y lo que falta es su fecha.
      tone={missingDate ? 'critical' : TONE[definition.family]}
      icon={definition.icon}
      help={coverageStateHelp(known)}
    >
      {missingDate ? t('coverage.missingFetchedAt') : coverageStateLabel(known)}
    </StatusBadge>
  )
}

/** La fecha de obtención, en su propia celda para que sobreviva a una exportación. */
export function CoverageFetchedAt({ state, fetchedAt }: Props) {
  if (state === 'UNKNOWN') {
    return <span className="text-muted-foreground text-sm">—</span>
  }
  return <DataTimestamp value={fetchedAt} emptyLabel={t('coverage.missingFetchedAt')} />
}

export function coverageStateHelp(state: string): string {
  if (!STATES[state]) return ''
  return t(`coverage.${state}.help` as TranslationKey)
}

/**
 * La etiqueta suelta, para los lugares donde no entra el badge entero — el
 * reparto por estado de `C-15`, por ejemplo.
 *
 * Vive acá y no en quien la usa para que las diez etiquetas tengan un solo
 * dueño: dos listas separadas terminan divergiendo, y el día que diverjan la
 * misma URL va a decir una cosa en la tabla y otra en el resumen.
 */
export function coverageStateLabel(state: string): string {
  if (!STATES[state]) return state
  return t(`coverage.${state}.label` as TranslationKey)
}
