"""Tests offline para comfyui_judge_image (impura: panel multi-juez por mayoria).

Sin GPU, sin red, sin servidor: monkeypatchea los tres jueces (estetico, fidelidad CLIP,
critico LLM) con stubs para probar la LOGICA de voto, agregacion y exclusion de jueces caidos.
"""

import os
import sys

sys.path.insert(0, os.path.dirname(__file__))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))

import ml.comfyui_judge_image as mod
from ml.comfyui_judge_image import comfyui_judge_image


def _aes(score, ok=True):
    return lambda image_path, **kw: {"ok": ok, "score_0_10": score, "error": "" if ok else "boom"}


def _clip(score, ok=True):
    return lambda image_path, prompt, **kw: {"ok": ok, "score_0_1": score, "error": "" if ok else "boom"}


def _llm(verdict, score=7.0, ok=True):
    return lambda image_path, prompt, **kw: {
        "ok": ok, "verdict": verdict, "score_0_10": score,
        "reasons": ["motivo"], "error": "" if ok else "boom"}


def _patch(monkeypatch, aes, clip, llm):
    monkeypatch.setattr(mod, "comfyui_score_aesthetic", aes)
    monkeypatch.setattr(mod, "comfyui_score_clip_alignment", clip)
    monkeypatch.setattr(mod, "comfyui_critique_image_llm", llm)


def test_tres_good_verdict_good(monkeypatch):
    _patch(monkeypatch, _aes(8.0), _clip(0.30), _llm("good"))
    res = comfyui_judge_image("i.png", "a cat")
    assert res["ok"] is True and res["verdict"] == "good"
    assert res["votes"] == {"aesthetic": "good", "clip": "good", "llm": "good"}
    # score = media de 8, 3.0(=0.30*10), 7 = 6.0
    assert abs(res["score"] - 6.0) < 1e-9


def test_mayoria_bad(monkeypatch):
    # estetico bajo (bad) + clip bajo (bad) + llm good -> 2 bad, 1 good -> bad.
    _patch(monkeypatch, _aes(2.0), _clip(0.05), _llm("good"))
    res = comfyui_judge_image("i.png", "p")
    assert res["verdict"] == "bad"


def test_empate_es_bad_conservador(monkeypatch):
    # 1 good (estetico) + 1 bad (clip) + 1 failed (llm) -> empate -> bad.
    _patch(monkeypatch, _aes(8.0), _clip(0.05), _llm("good", ok=False))
    res = comfyui_judge_image("i.png", "p")
    assert res["votes"]["llm"] == "failed"
    assert res["verdict"] == "bad"


def test_juez_caido_se_excluye_no_crashea(monkeypatch):
    # estetico falla pero el panel sigue votando con los otros dos.
    _patch(monkeypatch, _aes(0.0, ok=False), _clip(0.30), _llm("good"))
    res = comfyui_judge_image("i.png", "p")
    assert res["ok"] is True
    assert res["votes"]["aesthetic"] == "failed"
    assert res["verdict"] == "good"


def test_tres_fallan_ok_false(monkeypatch):
    _patch(monkeypatch, _aes(0.0, ok=False), _clip(0.0, ok=False), _llm("", ok=False))
    res = comfyui_judge_image("i.png", "p")
    assert res["ok"] is False and "los tres jueces fallaron" in res["error"]


def test_weights_afectan_score_no_voto(monkeypatch):
    _patch(monkeypatch, _aes(10.0), _clip(0.30), _llm("good", score=0.0))
    base = comfyui_judge_image("i.png", "p")
    # subir el peso del estetico (10) y anular el del llm (0) sube el score agregado.
    weighted = comfyui_judge_image("i.png", "p", weights={"aesthetic": 5.0, "llm": 0.0})
    assert weighted["score"] > base["score"]
    assert weighted["verdict"] == base["verdict"] == "good"
