"""
Reescribe las claves del resumen de cada lote al inglés.

`Batch.summary` es un JSON con forma libre, así que el renombrado de sus claves
no lo hace el esquema: hay que tocar las filas. Sin esta migración, los lotes
guardados antes del cambio quedarían con claves que ya nadie lee —la ficha
mostraría un lote de dos mil URLs sin una sola cifra— y no habría error en
ninguna parte que lo delatara.

Las dos direcciones están escritas. La vuelta atrás importa tanto como la ida:
sin ella, revertir el despliegue dejaría los lotes migrados ilegibles para el
código viejo, que es justo el momento en que uno menos quiere sorpresas.

Se recorre en lotes de quinientos y se escribe con `bulk_update`: son filas con
un JSON adentro, y una consulta por fila sobre una tabla que crece con cada
ciclo diario es de las que tardan lo suficiente como para que alguien corte el
despliegue por la mitad.
"""

from django.db import migrations

#: Claves del resumen de inspección, en el orden en que las escribe el servicio.
INSPECTION = {
    'consultadas': 'queried',
    'con_cambio': 'changed',
    'sin_cambio': 'unchanged',
    'fallidas': 'failed',
    'pendientes': 'pending',
    'cupo_concedido': 'quota_granted',
    'cupo_pedido': 'quota_requested',
}

#: Claves del resumen de sincronización.
SYNC = {
    'sitemaps_leidos': 'sitemaps_read',
    'sitemaps_enviados': 'sitemaps_submitted',
    'sitemaps_sin_cambios': 'sitemaps_unchanged',
    'urls_nuevas': 'new_urls',
    'urls_vistas': 'seen_urls',
    'urls_fuera_del_sitemap': 'urls_out_of_sitemap',
    'urls_ajenas': 'foreign_urls',
}

#: La comparten los dos resúmenes.
COMMON = {'errores': 'errors'}

RENAMES = INSPECTION | SYNC | COMMON

BATCH_SIZE = 500


def _rewrite(apps, mapping) -> None:
    Batch = apps.get_model('jobs', 'Batch')

    pending = []
    for batch in Batch.objects.exclude(summary={}).iterator(chunk_size=BATCH_SIZE):
        summary = batch.summary or {}
        if not isinstance(summary, dict):
            continue

        # Se conserva el orden de inserción y las claves que no estén en la
        # tabla: un resumen puede traer algo que este mapa no conozca, y
        # descartarlo silenciosamente sería perder dato en una migración.
        translated = {mapping.get(key, key): value for key, value in summary.items()}
        if translated == summary:
            continue

        batch.summary = translated
        pending.append(batch)

        if len(pending) >= BATCH_SIZE:
            Batch.objects.bulk_update(pending, ['summary'])
            pending.clear()

    if pending:
        Batch.objects.bulk_update(pending, ['summary'])


def to_english(apps, _schema_editor):
    _rewrite(apps, RENAMES)


def to_spanish(apps, _schema_editor):
    _rewrite(apps, {english: spanish for spanish, english in RENAMES.items()})


class Migration(migrations.Migration):
    dependencies = [('jobs', '0001_initial')]

    operations = [migrations.RunPython(to_english, to_spanish)]
