"""Integration tests for /api/scenarios versioning (ticket 03).

场景版本由系统维护（ADR-0001）：仅考纲字段（cases / model_bindings /
llm_config）变更时递增，元数据编辑不升版，API 不接受外部指定版本。
"""

import pytest
from agenteval.services.model_configs import ModelConfigService, SecretCipher
from agenteval.web.app import app
from cryptography.fernet import Fernet
from httpx import ASGITransport, AsyncClient

pytestmark = pytest.mark.anyio


@pytest.fixture()
def scenario_client(db_session, monkeypatch):
    from agenteval.web import app as app_module

    monkeypatch.setattr(app_module, "init_db", lambda: None)

    from agenteval.web.deps import get_db

    def _test_get_db():
        try:
            yield db_session
        finally:
            pass

    app.dependency_overrides[get_db] = _test_get_db
    yield db_session
    app.dependency_overrides.clear()


def _client() -> AsyncClient:
    return AsyncClient(transport=ASGITransport(app=app), base_url="http://test")


_BODY = {
    "name": "版本测试场景",
    "description": "初始",
    "tags": ["v"],
    "cases": [{"id": "c1", "type": "single", "messages": ["hi"]}],
}


async def _create(client) -> dict:
    resp = await client.post("/api/scenarios", json=_BODY)
    assert resp.status_code == 200, resp.text
    return resp.json()


async def test_create_scenario_version_starts_at_1(scenario_client):
    async with _client() as client:
        created = await _create(client)
        assert created["version"] == 1


async def test_editing_cases_bumps_version(scenario_client):
    async with _client() as client:
        created = await _create(client)
        body = {**_BODY, "cases": _BODY["cases"] + [{"id": "c2", "type": "single", "messages": ["yo"]}]}
        resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
        assert resp.status_code == 200
        assert resp.json()["version"] == 2


async def test_editing_llm_config_bumps_version(scenario_client):
    async with _client() as client:
        created = await _create(client)
        body = {**_BODY, "llm_config": {"model": "gpt-x"}}
        resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
        assert resp.json()["version"] == 2


async def test_editing_model_bindings_bumps_version(scenario_client, db_session):
    service = ModelConfigService(db_session, SecretCipher(Fernet.generate_key().decode("ascii")))
    config = service.create(
        name="judge", provider="openai_compatible", capability="chat",
        endpoint_url="https://m.example.com/v1/chat/completions",
        model_name="m", api_key="k", enabled=True, is_default=False, description="",
    )
    async with _client() as client:
        created = await _create(client)
        body = {**_BODY, "model_bindings": {"judge": config.id}}
        resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
        assert resp.status_code == 200, resp.text
        assert resp.json()["version"] == 2


async def test_metadata_edit_does_not_bump_version(scenario_client):
    async with _client() as client:
        created = await _create(client)
        body = {**_BODY, "name": "改名了", "description": "新描述", "tags": ["x", "y"]}
        resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
        assert resp.status_code == 200
        assert resp.json()["version"] == 1
        assert resp.json()["name"] == "改名了"


async def test_resaving_identical_syllabus_does_not_bump_version(scenario_client):
    """原样重存（考纲逐字节相同）不升版——序列化形态回归护栏。"""
    async with _client() as client:
        created = await _create(client)
        resp = await client.put(f"/api/scenarios/{created['id']}", json=_BODY)
        assert resp.status_code == 200
        assert resp.json()["version"] == 1


async def test_external_version_is_ignored(scenario_client):
    async with _client() as client:
        resp = await client.post("/api/scenarios", json={**_BODY, "version": 99})
        assert resp.json()["version"] == 1

        created = resp.json()
        body = {**_BODY, "version": 42}  # 元数据未变、考纲未变 → 版本保持 1
        resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
        assert resp.json()["version"] == 1


async def test_list_and_get_return_version(scenario_client):
    async with _client() as client:
        created = await _create(client)
        listed = (await client.get("/api/scenarios")).json()
        assert all("version" in s for s in listed)
        got = (await client.get(f"/api/scenarios/{created['id']}")).json()
        assert got["version"] == 1
