"""Unit tests: request body builders."""

import pytest

from seaart._enums import ImageSize
from seaart._internal._builders.images import (
    build_img_to_text_body,
    build_smart_edit_body,
    build_text_to_img_body,
)
from seaart._internal._builders.characters import (
    build_character_chat_body,
    build_character_voice_chat_body,
    build_settings_character_chat_body,
)
from seaart.options import TextToImgOptions


# ── Image builders ───────────────────────────────────────────────────────────

_DEFAULTS = dict(
    model_no="m1",
    model_ver_no="v1",
    prompt="a cat",
    image_url=None,
    seed_value=42,
    gen_mode="quality",
    image_size=ImageSize.SQUARE,
    num_images=1,
    free_creation=None,
    prompt_magic=None,
    options=TextToImgOptions(),
)


class TestBuildTextToImg:
    def test_basic_fields(self) -> None:
        body = build_text_to_img_body(**_DEFAULTS)  # type: ignore[arg-type]
        assert body.model_no == "m1"
        assert body.model_ver_no == "v1"
        assert body.meta.prompt == "a cat"
        assert body.meta.seed == 42
        assert body.meta.n_iter == 1

    def test_gen_mode_quality(self) -> None:
        body = build_text_to_img_body(**{**_DEFAULTS, "gen_mode": "quality"})  # type: ignore[arg-type]
        assert body.meta.generate is not None
        assert body.meta.generate.gen_mode == 1

    def test_gen_mode_other(self) -> None:
        body = build_text_to_img_body(**{**_DEFAULTS, "gen_mode": "speed"})  # type: ignore[arg-type]
        assert body.meta.generate is not None
        assert body.meta.generate.gen_mode == 0

    @pytest.mark.parametrize(
        ("free_creation", "expected"),
        [(None, 1), (False, 2), (True, 3)],
    )
    def test_speed_type(self, free_creation: bool | None, expected: int) -> None:
        body = build_text_to_img_body(**{**_DEFAULTS, "free_creation": free_creation})  # type: ignore[arg-type]
        assert body.speed_type == expected

    @pytest.mark.parametrize(
        ("prompt_magic", "expected"),
        [(None, 2), (False, 1), (True, 0)],
    )
    def test_prompt_magic_mode(self, prompt_magic: bool | None, expected: int) -> None:
        body = build_text_to_img_body(**{**_DEFAULTS, "prompt_magic": prompt_magic})  # type: ignore[arg-type]
        assert body.meta.generate is not None
        assert body.meta.generate.prompt_magic_mode == expected

    def test_image_size(self) -> None:
        body = build_text_to_img_body(**{**_DEFAULTS, "image_size": ImageSize.PORTRAIT_2_3})  # type: ignore[arg-type]
        assert body.meta.width == 2
        assert body.meta.height == 3

    def test_image_url_creates_conds(self) -> None:
        body = build_text_to_img_body(**{**_DEFAULTS, "image_url": "https://example.com/img.png"})  # type: ignore[arg-type]
        assert body.meta.lab_base is not None
        assert body.meta.lab_base.conds is not None
        assert len(body.meta.lab_base.conds) == 1

    def test_no_image_url_empty_conds(self) -> None:
        body = build_text_to_img_body(**_DEFAULTS)  # type: ignore[arg-type]
        assert body.meta.lab_base is not None
        assert body.meta.lab_base.conds == []


class TestBuildImgToText:
    def test_basic(self) -> None:
        body = build_img_to_text_body(url="https://example.com/img.png")
        assert body.meta.img_2_text.uri == "https://example.com/img.png"
        assert body.ss is None

    def test_with_ss(self) -> None:
        body = build_img_to_text_body(url="https://example.com/img.png", ss=1)
        assert body.ss == 1


class TestBuildSmartEdit:
    def test_basic(self) -> None:
        body = build_smart_edit_body(
            prompt="add hat",
            image_url="https://example.com/img.png",
            apply_id="ap1",
            is_use_unlimited_free=True,
            task_flow_version="v2",
            node_type_2="TextNode",
        )
        assert body.apply_id == "ap1"
        assert len(body.inputs) == 2
        assert body.inputs[0].val == "https://example.com/img.png"
        assert body.inputs[1].val == "add hat"


# ── Character builders ───────────────────────────────────────────────────────


class TestBuildCharacterChat:
    def test_basic(self) -> None:
        body = build_character_chat_body(
            content="hello",
            session_id="s1",
            model="gpt-4",
            vip_only=2,
            support_voice=1,
            refer="",
            stream=True,
        )
        assert body.content == "hello"
        assert body.session_id == "s1"
        assert body.stream is True
        assert body.vip_only == 2

    def test_with_history(self) -> None:
        from seaart._internal._schemas.characters.characters_chat import (
            HistoryMessage,
            Message,
        )

        msg = Message(role="text", content="hi")
        hist = [HistoryMessage(role=1, content="prev", msg_id="m1")]
        body = build_character_chat_body(
            content="hello",
            session_id="s1",
            model="gpt-4",
            vip_only=0,
            support_voice=0,
            refer="",
            stream=False,
            messages=msg,
            history_message=hist,
        )
        assert body.messages is not None
        assert len(body.messages) == 1
        assert body.history_message is not None
        assert len(body.history_message) == 1


class TestBuildCharacterVoice:
    def test_basic(self) -> None:
        body = build_character_voice_chat_body(
            msg_id="m1", timbre_id="t1"
        )
        assert body.msg_id == "m1"
        assert body.timbre_id == "t1"
        assert body.sub_msg_id is None

    def test_with_sub_msg_id(self) -> None:
        body = build_character_voice_chat_body(
            msg_id="m1", sub_msg_id="sub1", timbre_id="t1"
        )
        assert body.sub_msg_id == "sub1"


class TestBuildSettings:
    def test_basic(self) -> None:
        body = build_settings_character_chat_body(character_id="c1")
        assert body.character_id == "c1"
        assert body.gpt_model is None

    def test_with_all_fields(self) -> None:
        body = build_settings_character_chat_body(
            account_id="a1",
            character_id="c1",
            gpt_model="gpt-4",
            temperature=0.7,
            diversity=0.5,
            length_of_reply=200,
        )
        assert body.temperature == 0.7
        assert body.gpt_model == "gpt-4"
