"""统一响应信封 ActionState（coord-cross-review.md §5.3 P0 整改）.

总裁裁决 §2.6 降级模式：success=true + error=null + data 内 degraded 字段.

成功：{success: true, data: T}
失败：{success: false, error: {code, message, details?, trace_id?}}
降级：{success: true, data: T, details: {degraded: true, degraded_reason: "..."}}.
"""

from typing import Any

from pydantic import BaseModel


class ActionStateError(BaseModel):
    """错误信息（失败时填充）."""

    code: str
    message: str
    details: dict[str, Any] | None = None
    trace_id: str | None = None


class ActionState[T](BaseModel):
    """统一响应信封（coord-cross-review.md §5.3 裁决）.

    成功：{success: true, data: T}
    失败：{success: false, error: {code, message, details?, trace_id?}}
    降级：{success: true, data: T, details: {degraded: true, degraded_reason: "..."}}
    （保留功能但数据可能不完整，降级不是错误）
    """

    success: bool
    data: T | None = None
    error: ActionStateError | None = None
    details: dict[str, Any] | None = None  # 降级标记放此字段，不放 error

    @classmethod
    def ok(cls, data: T, *, degraded: bool = False, degraded_reason: str = "") -> "ActionState[T]":
        """成功响应（降级时 degraded=True）."""
        if degraded:
            details: dict[str, Any] = {"degraded": True}
            if degraded_reason:
                details["degraded_reason"] = degraded_reason
            return cls(success=True, data=data, error=None, details=details)
        return cls(success=True, data=data, error=None, details=None)

    @classmethod
    def fail(
        cls,
        code: str,
        message: str,
        *,
        trace_id: str | None = None,
        details: dict[str, Any] | None = None,
    ) -> "ActionState[T]":
        """失败响应."""
        return cls(
            success=False,
            data=None,
            error=ActionStateError(code=code, message=message, details=details, trace_id=trace_id),
        )
