"""
Reescribe los pedidos de Concrete Overlay guardados para la pregunta de forma.

El overlay tenía un campo `pattern` con una sola opción, `natural_stone_cut`,
que no se dibujaba. Ahora es `shape`, con `regular` e `irregular`. Hasta hoy
todas las fotos de piedra eran irregulares, así que un pedido viejo pasa a
`irregular`: es lo que la persona vio al elegir. Sin esta migración, un pedido
abierto para «ajustar y volver a generar» llegaría con una clave que el
catálogo ya no conoce, y su resumen buscaría un rótulo que ya no existe.

Las fotos irregulares, además, se mudaron a su propia carpeta, al lado de las
regulares. Cada pedido guarda las rutas de las muestras que mandó al modelo
(`references`), y la tarea las abre tal cual: una ruta vieja daría
`REFERENCE_MISSING` al volver a correr el pedido. También se reescriben.

Las dos direcciones están escritas. La vuelta pierde un dato: la forma vieja no
distinguía `regular`, y cualquier forma vuelve como `natural_stone_cut`.
"""

from django.db import migrations

OVERLAY = 'concrete_overlay'
OLD_FOLDER = 'ai/concrete_overlay/stone_color/'
NEW_FOLDER = 'ai/concrete_overlay/stone_color/irregular/'
OLD_PATTERN = 'natural_stone_cut'
SHAPE_OF_THE_OLD_PATTERN = 'irregular'

BATCH_SIZE = 500


def _to_shape(answers: dict) -> dict:
    """De `pattern` a `shape`, en el mismo lugar del orden de las respuestas."""
    if 'pattern' not in answers:
        return answers
    return {
        ('shape' if key == 'pattern' else key): (
            SHAPE_OF_THE_OLD_PATTERN if key == 'pattern' else value
        )
        for key, value in answers.items()
    }


def _to_pattern(answers: dict) -> dict:
    """De `shape` a `pattern`, que tenía una sola opción."""
    if 'shape' not in answers:
        return answers
    return {
        ('pattern' if key == 'shape' else key): (OLD_PATTERN if key == 'shape' else value)
        for key, value in answers.items()
    }


def _to_shape_folder(path: str) -> str:
    """Una muestra suelta en la carpeta del color pasa a la de las irregulares."""
    if path.startswith(OLD_FOLDER) and '/' not in path[len(OLD_FOLDER) :]:
        return NEW_FOLDER + path[len(OLD_FOLDER) :]
    return path


def _to_flat_folder(path: str) -> str:
    if path.startswith(NEW_FOLDER):
        return OLD_FOLDER + path[len(NEW_FOLDER) :]
    return path


def _rewrite(apps, convert_answers, convert_path) -> None:
    ImageGeneration = apps.get_model('ai', 'ImageGeneration')

    pending = []
    for generation in ImageGeneration.objects.exclude(areas=[]).iterator(chunk_size=BATCH_SIZE):
        areas = generation.areas
        if not isinstance(areas, list):
            continue

        rewritten = [
            {**container, 'answers': convert_answers(container['answers'])}
            if isinstance(container, dict)
            and container.get('service') == OVERLAY
            and isinstance(container.get('answers'), dict)
            else container
            for container in areas
        ]
        references = generation.references
        if isinstance(references, list):
            moved = [convert_path(path) if isinstance(path, str) else path for path in references]
        else:
            moved = references
        if rewritten == areas and moved == references:
            continue

        generation.areas = rewritten
        generation.references = moved
        pending.append(generation)

        if len(pending) >= BATCH_SIZE:
            ImageGeneration.objects.bulk_update(pending, ['areas', 'references'])
            pending.clear()

    if pending:
        ImageGeneration.objects.bulk_update(pending, ['areas', 'references'])


def to_shape(apps, _schema_editor):
    _rewrite(apps, _to_shape, _to_shape_folder)


def to_pattern(apps, _schema_editor):
    _rewrite(apps, _to_pattern, _to_flat_folder)


class Migration(migrations.Migration):
    dependencies = [('ai', '0013_coping_as_one_answer')]

    operations = [migrations.RunPython(to_shape, to_pattern)]
