"""
Las marcas que la persona dibuja sobre la foto, y cómo viajan al modelo.

Las marcas son **un extra** sobre el pedido: las opciones del catálogo dicen
qué se hace en cada área, y el dibujo sólo precisa dónde. **El código no
interpreta las marcas**: no nombra colores ni los relaciona con nada. Qué se
marcó, con qué color y para qué lo dice la persona en la nota, en lenguaje
natural; una marca que la nota no menciona se ignora. Por eso nada de lo
que se arma acá recorta el resultado ni reemplaza una sección del prompt: el
resultado del proveedor se usa tal cual (D4 de la task
`ai-image-annotation-layer`).

Cómo viajan lo decide un **modo**, que se elige en «Config» y no en código:
la prueba a mano no alcanzó para fijarlo y la decisión se itera con fotos
reales (D3, D6). El modo es **sólo la forma** en que viaja el dibujo, siempre
junto con la foto original, como una imagen más:

- la **copia anotada**: la foto con los trazos quemados encima;
- la **capa**: sólo los trazos, sobre fondo transparente y del tamaño de la
  foto, tal cual se dibujaron.

Ningún modo cambia lo que significan las marcas ni la nota. Por eso no se usa
el parámetro `mask` del proveedor: una máscara no es una forma de mandar el
dibujo sino una regla —«editá sólo lo pintado»—, y armada con todo lo pintado
contradecía una nota que pedía proteger una zona marcada. Existió como modo y
se sacó por eso.

El modo se congela con el pedido y no se lee al ejecutar, al revés que el
modelo y la calidad: la frase del prompt que describe la imagen depende de él,
y el prompt se arma al pedir.
"""

from dataclasses import dataclass

from django.db import models

from apps.ai import images


class MarkupMode(models.TextChoices):
    """En qué forma viaja el dibujo, además de la foto, cuando el pedido trae marcas."""

    COPY = 'copy', 'Original + annotated copy'
    LAYER = 'layer', 'Original + transparent layer'


#: Con qué arranca la configuración. Es la forma que mejor ubicó las zonas en la
#: prueba a mano (fase 0). No es una conclusión cerrada; por eso es configurable.
DEFAULT_MODE = MarkupMode.COPY


#: Los colores con que arranca el pincel, en el orden en que se muestran. Son
#: sólo de la pantalla: el servidor no los valida ni los manda al modelo. Son
#: los «recientes» de una sesión nueva: cada color que se elige a mano entra
#: primero y empuja al último afuera. Tres que no se confunden entre sí ni con
#: lo que suele haber en un patio: sin verde, que se pierde en el césped, ni
#: gris, que se pierde en el concreto.
DEFAULT_COLORS: tuple[str, ...] = ('#ef4444', '#facc15', '#3b82f6')


def sends_layer(mode: str) -> bool:
    """
    Si el dibujo viaja como capa transparente.

    Cualquier otro valor viaja como copia anotada, incluidos los de los pedidos
    que se hicieron con los modos de máscara, que ya no existen: la copia es la
    forma que el modelo sabe leer sin que nadie le explique la capa.
    """
    return mode == MarkupMode.LAYER


@dataclass(frozen=True)
class ProviderInputs:
    """
    Lo que las marcas agregan a la llamada, ya resuelto por el modo.

    Cada archivo va como la tupla `(nombre, bytes, tipo)` que el SDK acepta en
    lugar de un archivo abierto: se arma en memoria y no tiene por qué tocar el
    disco.
    """

    #: Las imágenes que van **al final** de la lista, después de las muestras
    #: del catálogo: así el número de cada muestra no cambia y el bloque de
    #: referencias sigue valiendo.
    extra_images: tuple[tuple[str, bytes, str], ...]


def provider_inputs(mode: str, source: bytes, markup: bytes) -> ProviderInputs:
    """El resolver: del modo congelado en el pedido a la imagen que se le suma a la llamada."""
    drawing = markup if sends_layer(mode) else images.annotated_copy(source, markup)
    return ProviderInputs(extra_images=(('markup.png', drawing, 'image/png'),))


def mode_props() -> list[str]:
    """Los modos para la pantalla «Config», como códigos; los rótulos los pone el catálogo."""
    return list(MarkupMode.values)


def default_color_props() -> list[str]:
    """Los colores con que arranca el pincel, como hex, en el orden en que se muestran."""
    return list(DEFAULT_COLORS)
