"""Tests de pixeloe_downscale — tolerantes al entorno.

El venv del registry NO trae `pixeloe`, asi que estas pruebas ejercitan el
"bridge" de interprete (subprocess al python de ComfyUI, que si la tiene). Si
tampoco hay ningun interprete con pixeloe disponible, la funcion debe degradar
limpiamente: ok=False con error no vacio y SIN lanzar excepcion.

Por eso cada test PASA en los dos escenarios:
  - pixeloe disponible (inproc o via bridge): assert sobre el resultado real.
  - pixeloe ausente en todos lados: assert sobre la degradacion no-throw.
Asi la suite es verde tanto en este PC (ComfyUI presente) como en uno sin ComfyUI,
y el contrato "no-throw" queda cubierto en ambos.
"""

import os
import sys

import numpy as np
from PIL import Image

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from ml.pixeloe_downscale import pixeloe_downscale  # noqa: E402


def _shapes_png(path, w=256, h=256):
    """PNG 256x256 RGB con un gradiente + formas (contraste con silueta clara)."""
    yy, xx = np.mgrid[0:h, 0:w]
    arr = np.zeros((h, w, 3), dtype=np.uint8)
    arr[..., 0] = (xx * 255 // max(1, w - 1)).astype(np.uint8)   # gradiente rojo
    arr[..., 1] = (yy * 255 // max(1, h - 1)).astype(np.uint8)   # gradiente verde
    # Bloque azul central: borde duro para que el modo "contrast" tenga silueta.
    arr[h // 4:3 * h // 4, w // 4:3 * w // 4, 2] = 255
    Image.fromarray(arr, "RGB").save(path)
    return path


def test_golden_downscale_64_or_clean_degrade(tmp_path):
    """Golden: 256x256 -> grid 64x64 (no_upscale). Si pixeloe no esta -> ok=False limpio."""
    src = _shapes_png(str(tmp_path / "raw.png"))
    dst = str(tmp_path / "grid64.png")
    res = pixeloe_downscale(src, dst, target_size=64, no_upscale=True)
    assert isinstance(res, dict)
    if res["ok"]:
        assert os.path.isfile(dst)
        assert res["size"] == [64, 64]          # no_upscale=True -> grid real
        assert res["error"] == ""
        assert res["via"] in ("inproc", "bridge")
        assert res["mode"] == "contrast"
        assert res["target_size"] == 64
    else:
        # Degradacion limpia: sin pixeloe en ningun interprete.
        assert res["error"] != ""
        assert res["via"] in ("", "bridge", "inproc")


def test_edge_target_size_32(tmp_path):
    """Edge: grid de 32 (iconos). size==[32,32] cuando pixeloe esta presente."""
    src = _shapes_png(str(tmp_path / "raw.png"))
    dst = str(tmp_path / "grid32.png")
    res = pixeloe_downscale(src, dst, target_size=32, no_upscale=True)
    if res["ok"]:
        assert res["size"] == [32, 32]
        assert res["target_size"] == 32
        assert os.path.isfile(dst)
    else:
        assert res["error"] != ""


def test_edge_mode_nearest_no_color_matching(tmp_path):
    """Edge: otro modo + color_matching off; debe seguir produciendo el grid o degradar."""
    src = _shapes_png(str(tmp_path / "raw.png"))
    dst = str(tmp_path / "near.png")
    res = pixeloe_downscale(
        src, dst, mode="nearest", target_size=64,
        color_matching=False, no_upscale=True,
    )
    assert isinstance(res, dict)
    if res["ok"]:
        assert res["mode"] == "nearest"
        assert res["size"] == [64, 64]
    else:
        assert res["error"] != ""


def test_error_missing_src_no_throw(tmp_path):
    """Error path: src inexistente -> ok=False, error explica, sin excepcion."""
    res = pixeloe_downscale(
        str(tmp_path / "nope.png"), str(tmp_path / "o.png"), target_size=64,
    )
    assert res["ok"] is False
    assert "no existe" in res["error"]
    assert res["size"] == [0, 0]


def test_error_no_interpreter_with_pixeloe(tmp_path):
    """Error path: forzar comfy_python invalido cuando el actual no tiene pixeloe.

    Si el interprete que corre el test YA tiene pixeloe (inproc), el comfy_python
    invalido se ignora y la llamada puede salir ok=True; el test sigue siendo
    valido (no-throw). Si NO lo tiene, no hay ningun interprete con pixeloe y debe
    devolver ok=False con error, nunca lanzar.
    """
    src = _shapes_png(str(tmp_path / "raw.png"))
    dst = str(tmp_path / "o.png")
    res = pixeloe_downscale(
        src, dst, target_size=64, comfy_python="/no/such/python-interpreter",
    )
    assert isinstance(res, dict)
    try:
        import pixeloe  # noqa: F401
        has_local = True
    except Exception:  # noqa: BLE001
        has_local = False
    if has_local:
        # pixeloe en el interprete del test -> ruta inproc, comfy_python ignorado.
        assert res["ok"] is True
    else:
        # comfy_python invalido + env vacio: si ~/ComfyUI/.venv existe, puede
        # bridgear y salir ok; si no, ok=False con error. Ambos no-throw.
        assert res["ok"] in (True, False)
        if not res["ok"]:
            assert res["error"] != ""
