"""
Los pedidos de indexación y la evidencia de cada uno.

Una fila por URL y por lote, y esa misma fila hace cuatro trabajos: es la lista
del lote antes de correr, el estado de cada dirección mientras corre, el orden
que permite reanudar sin reenviar, y la prueba de lo que se mandó y de lo que
Google contestó. Separarlas en cuatro tablas obligaría a mantenerlas
sincronizadas, y el día que se desincronicen la que miente es la evidencia.
"""

from django.db import models

from apps.core.models import BaseModel


class IndexingState(models.TextChoices):
    """
    En qué punto está el pedido de una dirección.

    `REMOVED` no es un fallo: es alguien que sacó esa URL del borrador antes de
    correrlo. Se marca en vez de borrar la fila porque el lote tiene que poder
    explicar qué se decidió no enviar, que es una parte del relato tan válida
    como lo que sí salió.
    """

    PENDING = 'PENDING', 'Not sent yet'
    SENT = 'SENT', 'Request sent'
    ERROR = 'ERROR', 'Google rejected it'
    REMOVED = 'REMOVED', 'Taken out of the batch'


class IndexingRequest(BaseModel):
    """
    Un pedido de indexación sobre una dirección, con las dos puntas guardadas.

    **Esta tabla no se purga nunca.** Es la única del producto con esa
    propiedad: las sesiones caducan a los noventa días y los archivos de
    exportación a los siete, porque los dos son cosas que se vuelven a generar.
    Una prueba de que el 14 de marzo se le pidió a Google que mirara una
    dirección no se puede volver a generar. Si alguien le agrega retención «por
    consistencia con el resto», el producto pierde exactamente aquello para lo
    que se construyó esta parte.

    **Nada de acá toca `Url.coverage_state`.** «Le pedimos que la indexe» y
    «Google dice que está indexada» son dos afirmaciones distintas, y encimarlas
    destruiría la evidencia en el mismo movimiento en que la genera.
    """

    batch = models.ForeignKey(
        'jobs.Batch', on_delete=models.CASCADE, related_name='indexing_requests'
    )
    # Admite nulo y no cae con la URL: la prueba tiene que sobrevivir a que la
    # dirección se borre del inventario. Por eso al lado va `loc`, que es una
    # copia congelada y no una desnormalización por velocidad.
    url = models.ForeignKey(
        'sitemaps.Url',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='indexing_requests',
    )
    #: La dirección tal como era al armar el lote. No se actualiza nunca: lo que
    #: se envió fue esto, aunque la fila de `Url` diga otra cosa hoy.
    loc = models.URLField(max_length=2000)
    #: El orden dentro del lote. Es lo que permite reanudar por donde iba en vez
    #: de contar cuántas se hicieron, que se equivoca en cuanto una queda en
    #: `REMOVED` o en `ERROR`.
    position = models.PositiveIntegerField()
    state = models.CharField(
        max_length=10, choices=IndexingState.choices, default=IndexingState.PENDING
    )
    sent_at = models.DateTimeField(null=True, blank=True)

    #: Lo que se le mandó a Google, crudo. Vacío mientras el lote es un borrador.
    request_body = models.JSONField(default=dict, blank=True)
    response_status = models.IntegerField(null=True, blank=True)
    #: Lo que contestó, crudo. Se guarda igual en el éxito y en el error: la
    #: respuesta que informa que se agotó la cuota es la que contesta «¿por qué
    #: se detuvo el lote?» y la que documenta que el límite existe y no lo
    #: inventó la aplicación.
    response_body = models.JSONField(default=dict, blank=True)
    #: El motivo ya clasificado, para poder ramificar sin leer la prosa (RT-08).
    error_code = models.CharField(max_length=30, blank=True, default='')
    error_message = models.TextField(blank=True, default='')

    class Meta:
        ordering = ['batch', 'position']
        constraints = [
            models.UniqueConstraint(
                fields=['batch', 'position'], name='one_position_per_indexing_batch'
            ),
            models.UniqueConstraint(
                fields=['batch', 'url'],
                condition=models.Q(url__isnull=False),
                name='one_indexing_request_per_url_and_batch',
            ),
        ]
        indexes = [
            models.Index(fields=['batch', 'state']),
            models.Index(fields=['url', '-created_at']),
        ]

    def __str__(self) -> str:
        return f'{self.loc} ({self.state})'

    @property
    def has_evidence(self) -> bool:
        """
        Si esta fila ya tiene algo que mostrar como prueba.

        Un borrador todavía no lo tiene, y decirlo explícitamente evita que la
        pantalla dibuje una ficha de evidencia vacía que parece un fallo.
        """
        return bool(self.request_body)
