"""ActionState 统一响应信封测试."""

from src.ai.models.action_state import ActionState, ErrorDetail
from src.ai.models.chat import ChatData, ChatResponse, Usage


class TestActionState:
    """ActionState 信封测试."""

    def test_ok_success(self) -> None:
        """ok() 返回成功响应."""
        data = ChatData(content="hello", model="gpt-4o", usage=Usage())
        resp = ActionState.ok(data)
        assert resp.success is True
        assert resp.data is not None
        assert resp.data.content == "hello"
        assert resp.error is None

    def test_error_response(self) -> None:
        """error_response() 返回错误响应."""
        resp = ActionState.error_response(
            code="AI_LLM_UNAVAILABLE",
            message="all providers failed",
            details={"tried": ["openai"]},
            trace_id="req-123",
        )
        assert resp.success is False
        assert resp.data is None
        assert resp.error is not None
        assert resp.error.code == "AI_LLM_UNAVAILABLE"
        assert resp.error.message == "all providers failed"
        assert resp.error.details == {"tried": ["openai"]}
        assert resp.error.trace_id == "req-123"

    def test_degraded_sets_flags(self) -> None:
        """degraded() 在 data 上设置 degraded + degraded_reason."""
        data = ChatData(content="fallback", model="gpt-4o", usage=Usage())
        resp = ActionState.degraded(data, "llm unavailable")
        assert resp.success is True
        assert resp.error is None
        assert resp.data is not None
        assert resp.data.degraded is True
        assert resp.data.degraded_reason == "llm unavailable"

    def test_error_detail_alias(self) -> None:
        """ErrorDetail 支持 traceId alias."""
        err = ErrorDetail(code="AI_INTERNAL_ERROR", message="boom", trace_id="t-1")
        assert err.trace_id == "t-1"
        # 序列化使用 alias
        dumped = err.model_dump(by_alias=True)
        assert dumped["traceId"] == "t-1"

    def test_chat_response_inherits_action_state(self) -> None:
        """ChatResponse 继承 ActionState[ChatData]."""
        data = ChatData(content="hi", model="m", usage=Usage())
        resp = ChatResponse.ok(data)
        assert resp.success is True
        assert resp.data.content == "hi"

    def test_error_response_without_optional_fields(self) -> None:
        """error_response() 可选字段缺省."""
        resp = ActionState.error_response("AI_INTERNAL_ERROR", "fail")
        assert resp.error is not None
        assert resp.error.details is None
        assert resp.error.trace_id is None
