"""Unit tests for PaginationEnvelope generic Pydantic model."""

from __future__ import annotations

from pydantic import BaseModel

from controllers.openapi._models import PaginationEnvelope


class _Row(BaseModel):
    id: str
    name: str


def test_envelope_basic_fields():
    env = PaginationEnvelope[_Row](page=1, limit=20, total=42, has_more=True, data=[_Row(id="a", name="A")])
    dumped = env.model_dump(mode="json")
    assert dumped == {
        "page": 1,
        "limit": 20,
        "total": 42,
        "has_more": True,
        "data": [{"id": "a", "name": "A"}],
    }


def test_envelope_empty_data_no_more():
    env = PaginationEnvelope[_Row](page=1, limit=20, total=0, has_more=False, data=[])
    assert env.model_dump(mode="json")["data"] == []
    assert env.model_dump(mode="json")["has_more"] is False


def test_envelope_has_more_true_when_total_exceeds_page_window():
    env = PaginationEnvelope[_Row].build(page=1, limit=20, total=42, items=[_Row(id="a", name="A")])
    assert env.has_more is True


def test_envelope_has_more_false_when_total_within_page_window():
    env = PaginationEnvelope[_Row].build(page=2, limit=20, total=22, items=[_Row(id="a", name="A")])
    assert env.has_more is False


def test_envelope_has_more_false_for_last_page():
    env = PaginationEnvelope[_Row].build(page=3, limit=20, total=42, items=[_Row(id="a", name="A")])
    assert env.has_more is False


def test_max_page_limit_is_200():
    from controllers.openapi._models import MAX_PAGE_LIMIT

    assert MAX_PAGE_LIMIT == 200


def test_envelope_uses_pep695_generics():
    """Verify the class uses PEP 695 native generic syntax (not legacy Generic[T])."""
    from controllers.openapi._models import PaginationEnvelope

    # PEP 695 syntax populates __type_params__; the legacy Generic[T] form does not.
    assert PaginationEnvelope.__type_params__, "expected PEP 695 native generic syntax"

    fields = PaginationEnvelope.model_fields
    assert {"page", "limit", "total", "has_more", "data"} <= set(fields)


def test_app_info_response_dump_matches_spec():
    from controllers.openapi._models import AppInfo

    obj = AppInfo(
        id="app1",
        name="X",
        description="d",
        mode="chat",
    )
    assert obj.model_dump(mode="json") == {
        "id": "app1",
        "name": "X",
        "description": "d",
        "mode": "chat",
    }


def test_app_describe_response_nests_info_and_parameters():
    from controllers.openapi._models import AppDescribeInfo, AppDescribeResponse

    info = AppDescribeInfo(
        id="app1",
        name="X",
        mode="chat",
        description=None,
        updated_at="2026-05-05T00:00:00+00:00",
        service_api_enabled=True,
    )
    obj = AppDescribeResponse(info=info, parameters={"opening_statement": None})
    dumped = obj.model_dump(mode="json")
    assert dumped["info"]["service_api_enabled"] is True
    assert dumped["parameters"]["opening_statement"] is None


def test_response_models_dump_per_mode():
    from controllers.openapi._models import (
        ChatMessageResponse,
        CompletionMessageResponse,
        WorkflowRunData,
        WorkflowRunResponse,
    )

    chat = ChatMessageResponse(
        event="message",
        task_id="t1",
        id="m1",
        message_id="m1",
        conversation_id="c1",
        mode="chat",
        answer="hi",
        created_at=0,
    )
    assert chat.model_dump(mode="json")["mode"] == "chat"
    wf = WorkflowRunResponse(
        workflow_run_id="r1",
        task_id="t1",
        data=WorkflowRunData(id="r1", workflow_id="w1", status="succeeded"),
    )
    assert wf.model_dump(mode="json")["data"]["status"] == "succeeded"
    assert wf.model_dump(mode="json")["mode"] == "workflow"
    comp = CompletionMessageResponse(
        event="message",
        task_id="t2",
        id="m2",
        message_id="m2",
        mode="completion",
        answer="ok",
        created_at=0,
    )
    assert comp.model_dump(mode="json")["mode"] == "completion"
