"""
Online serving tests: text-to-image.
See examples/online_serving/text_to_image/README.md

The output materials are organized in a three-level directory structure:
- Set at init: `self.output_root` for all tests (from env OUTPUT_DIR)
- Set at `self.run(...)`: `output_subfolder` for a specific example page (e.g., `example_offline_t2i`)
- Generated by `extract_readme_snippets`: `snippet.test_id` for a specific code block (matching H2 titles, e.g., `basic_usage_001`)
"""

import sys
from pathlib import Path

import pytest

from tests.examples.helpers import EXAMPLES, OUTPUT_DIR, run_cmd, write_zimage_lora
from tests.helpers.assertions import assert_image_valid
from tests.helpers.mark import hardware_marks
from tests.helpers.runtime import OmniServer, OmniServerParams

pytestmark = [pytest.mark.full_model, pytest.mark.example, *hardware_marks(res={"cuda": "H100"})]

T2I_ONLINE_CLIENT = EXAMPLES / "online_serving" / "text_to_image" / "openai_chat_client.py"
EXAMPLE_OUTPUT_SUBFOLDER = "example_online_t2i"


@pytest.fixture(scope="module")
def example_output_dir() -> Path:
    d = OUTPUT_DIR / EXAMPLE_OUTPUT_SUBFOLDER
    d.mkdir(parents=True, exist_ok=True)
    return d


# Ensuring two indirect parametrization receive exactly the same parameter list.
# Then, only one omni_server instance is started for all test functions using this param set.
# Two additional pre-requisites:
# - omni_server must (and indeed is) defined as a module-scoped fixture
# - test functions sharing the same param set must be adjacent to each other
qwen_image_server_params = [OmniServerParams(model="Qwen/Qwen-Image")]
z_image_turbo_server_params = [OmniServerParams(model="Tongyi-MAI/Z-Image-Turbo")]


# --- ### Method 1: Using curl ---


@pytest.mark.parametrize("omni_server", qwen_image_server_params, indirect=True)
def test_api_calls_001(omni_server: OmniServer, example_output_dir: Path):
    url = f"http://{omni_server.host}:{omni_server.port}/v1/chat/completions"
    case_dir = example_output_dir / "api_calls-001"
    case_dir.mkdir(parents=True, exist_ok=True)
    out = case_dir / "api_calls_001.png"
    json_str = """{
    "messages": [
      {"role": "user", "content": "A beautiful landscape painting"}
    ],
    "extra_body": {
      "height": 1024,
      "width": 1024,
      "num_inference_steps": 50,
      "true_cfg_scale": 4.0,
      "seed": 42
    }
}"""
    run_cmd(
        f"curl -s '{url}'"
        " -H 'Content-Type: application/json'"
        f" -d '{json_str}'"
        " | jq -r '.choices[0].message.content[0].image_url.url'"
        f" | cut -d',' -f2- | base64 -d > '{out}'",
        shell=True,
    )
    assert_image_valid(out, width=1024, height=1024)


# --- ### Method 2: Using Python Client ---


@pytest.mark.parametrize("omni_server", qwen_image_server_params, indirect=True)
def test_api_calls_002(omni_server: OmniServer, example_output_dir: Path):
    case_dir = example_output_dir / "api_calls-002"
    case_dir.mkdir(parents=True, exist_ok=True)
    out = case_dir / "api_calls_002.png"
    run_cmd(
        [
            sys.executable,
            str(T2I_ONLINE_CLIENT),
            "--prompt",
            "A beautiful landscape painting",
            "--output",
            str(out),
            "--server",
            f"http://{omni_server.host}:{omni_server.port}",
        ]
    )
    assert_image_valid(out)


@pytest.mark.skip("README section 'Method 3: Using Gradio Demo' is intentionally excluded for examples tests")
def test_api_calls_003(): ...


# --- ### Using Python Client with LoRA ---


@pytest.mark.parametrize("omni_server", z_image_turbo_server_params, indirect=True)
def test_lora_001(omni_server: OmniServer, example_output_dir: Path, tmp_path: Path):
    lora_dir = tmp_path / "zimage_lora_a"
    write_zimage_lora(lora_dir, v_scale=8.0)
    case_dir = example_output_dir / "lora-001"
    case_dir.mkdir(parents=True, exist_ok=True)
    out = case_dir / "lora_001.png"
    run_cmd(
        [
            sys.executable,
            str(T2I_ONLINE_CLIENT),
            "--prompt",
            "A piece of cheesecake",
            "--lora-path",
            str(lora_dir),
            "--lora-name",
            "a",
            "--lora-scale",
            "1.0",
            "--output",
            str(out),
            "--server",
            f"http://{omni_server.host}:{omni_server.port}",
        ]
    )
    assert_image_valid(out)


# --- ### Using curl with LoRA (Images API) ---


@pytest.mark.skip(reason="Covered by tests/diffusion/lora/test_images_generations_lora.py")
def test_lora_002(): ...
