"""Tests para genconfig_to_diffusers_kwargs."""

import sys
import os
import unittest

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

from ml.genconfig_to_diffusers_kwargs import genconfig_to_diffusers_kwargs
from ml.generation_config import GenerationConfig


def _make_cfg(**overrides):
    """Crea un GenerationConfig sintetico para tests via model_validate / constructor."""
    defaults = dict(
        prompt="a dog in the park",
        seed=42,
        steps=30,
        cfg_scale=7.5,
        sampler="euler_a",
        width=512,
        height=768,
        model={"name": "runwayml/stable-diffusion-v1-5", "model_type": "sd15"},
    )
    defaults.update(overrides)
    try:
        return GenerationConfig.model_validate(defaults)
    except AttributeError:
        # dataclass fallback: model y loras ya son dicts, construir manualmente
        from ml.model_ref import ModelRef
        from ml.lora_ref import LoraRef
        m = defaults.pop("model")
        if isinstance(m, dict):
            m = ModelRef(**m)
        loras = defaults.pop("loras", [])
        built_loras = []
        for lr in loras:
            if isinstance(lr, dict):
                built_loras.append(LoraRef(**lr))
            else:
                built_loras.append(lr)
        return GenerationConfig(model=m, loras=tuple(built_loras), **defaults)


class TestGenconfigToDiffusersKwargs(unittest.TestCase):

    def test_kwargs_contiene_todas_las_claves_requeridas(self):
        """kwargs contiene todas las claves requeridas"""
        cfg = _make_cfg()
        kwargs = genconfig_to_diffusers_kwargs(cfg)
        required_keys = {
            "prompt",
            "negative_prompt",
            "num_inference_steps",
            "guidance_scale",
            "width",
            "height",
            "generator",
        }
        self.assertEqual(set(kwargs.keys()), required_keys)

    def test_negative_prompt_none_se_pasa_tal_cual(self):
        """negative_prompt None se pasa tal cual"""
        cfg = _make_cfg(negative_prompt=None)
        kwargs = genconfig_to_diffusers_kwargs(cfg)
        self.assertIsNone(kwargs["negative_prompt"])

    def test_steps_y_cfg_scale_se_mapean_a_num_inference_steps_y_guidance_scale(self):
        """steps y cfg_scale se mapean a num_inference_steps y guidance_scale"""
        cfg = _make_cfg(steps=20, cfg_scale=8.0)
        kwargs = genconfig_to_diffusers_kwargs(cfg)
        self.assertEqual(kwargs["num_inference_steps"], 20)
        self.assertAlmostEqual(kwargs["guidance_scale"], 8.0)

    def test_generator_siempre_es_none(self):
        """generator siempre es None"""
        cfg = _make_cfg()
        kwargs = genconfig_to_diffusers_kwargs(cfg)
        self.assertIsNone(kwargs["generator"])

    def test_prompt_se_copia_sin_modificar(self):
        """prompt se copia sin modificar"""
        cfg = _make_cfg(prompt="a cat on a roof")
        kwargs = genconfig_to_diffusers_kwargs(cfg)
        self.assertEqual(kwargs["prompt"], "a cat on a roof")

    def test_width_y_height_se_preservan(self):
        """width y height se preservan"""
        cfg = _make_cfg(width=1024, height=768)
        kwargs = genconfig_to_diffusers_kwargs(cfg)
        self.assertEqual(kwargs["width"], 1024)
        self.assertEqual(kwargs["height"], 768)

    def test_negative_prompt_string_se_pasa_tal_cual(self):
        """negative_prompt string se pasa tal cual"""
        cfg = _make_cfg(negative_prompt="blurry, low quality")
        kwargs = genconfig_to_diffusers_kwargs(cfg)
        self.assertEqual(kwargs["negative_prompt"], "blurry, low quality")

    def test_no_incluye_seed_sampler_ni_loras(self):
        """no incluye seed sampler ni loras en el dict"""
        cfg = _make_cfg(
            loras=[{"path": "/loras/detail.safetensors", "weight": 0.8}]
        )
        kwargs = genconfig_to_diffusers_kwargs(cfg)
        self.assertNotIn("seed", kwargs)
        self.assertNotIn("sampler", kwargs)
        self.assertNotIn("loras", kwargs)


if __name__ == "__main__":
    unittest.main()
