"""EDA Agent state dataclasses and serializers."""
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional


class BeliefSource(Enum):
    """信念来源类型"""
    PERCEPTION = "perception"          # 直接感知
    INFERENCE = "inference"            # 推理得出
    COMMUNICATION = "communication"    # 他人告知
    HUMAN_CONFIRMED = "human_confirmed"  # 人工确认


class NormType(Enum):
    """规范类型"""
    OBLIGATION = "obligation"          # 义务
    PROHIBITION = "prohibition"       # 禁止
    PERMISSION = "permission"          # 许可


@dataclass
class Belief:
    """E 组件：单条信念"""
    id: str
    proposition: str                   # 命题内容
    confidence: float                  # 置信度 [0, 1]
    source: BeliefSource               # 来源
    norm_refs: List[str] = field(default_factory=list)
    timestamp: datetime = field(default_factory=datetime.now)
    requires_human_confirmation: bool = False


@dataclass
class NormBinding:
    """D 组件：规范绑定"""
    norm_id: str
    norm_type: NormType
    condition_met: bool                # 条件是否满足
    action_required: str               # 要求的行动
    action_prohibited: List[str] = field(default_factory=list)
    sanction: Optional[Dict] = None    # 制裁措施
    bound_at: datetime = field(default_factory=datetime.now)


@dataclass
class ValueWeight:
    """A 组件：价值权重"""
    value_name: str
    weight: float                     # [0, 1]
    hierarchy: int                     # 优先级层级
    rationale: str


@dataclass
class EDAState:
    """完整的 EDA Agent 状态"""
    agent_id: str
    agent_role: str
    
    # E 组件
    beliefs: Dict[str, Belief] = field(default_factory=dict)
    
    # D 组件
    norm_bindings: List[NormBinding] = field(default_factory=list)
    
    # A 组件
    value_weights: List[ValueWeight] = field(default_factory=list)

    # 当前激活的信息场
    active_fields: List[str] = field(default_factory=list)
    
    # 当前意图
    current_intention: Optional[str] = None
    
    # 信任评分
    trust_score: float = 0.8
    
    # 状态元数据
    created_at: datetime = field(default_factory=datetime.now)
    updated_at: datetime = field(default_factory=datetime.now)

    def to_dict(self) -> Dict[str, Any]:
        """Serialize nested dataclasses into a JSON-friendly dict."""
        return {
            "agent_id": self.agent_id,
            "agent_role": self.agent_role,
            "beliefs": {
                key: {
                    "id": belief.id,
                    "proposition": belief.proposition,
                    "confidence": belief.confidence,
                    "source": belief.source.value,
                    "norm_refs": belief.norm_refs,
                    "timestamp": belief.timestamp.isoformat(),
                    "requires_human_confirmation": belief.requires_human_confirmation,
                }
                for key, belief in self.beliefs.items()
            },
            "norm_bindings": [
                {
                    "norm_id": binding.norm_id,
                    "norm_type": binding.norm_type.value,
                    "condition_met": binding.condition_met,
                    "action_required": binding.action_required,
                    "action_prohibited": binding.action_prohibited,
                    "sanction": binding.sanction,
                    "bound_at": binding.bound_at.isoformat(),
                }
                for binding in self.norm_bindings
            ],
            "value_weights": [
                {
                    "value_name": vw.value_name,
                    "weight": vw.weight,
                    "hierarchy": vw.hierarchy,
                    "rationale": vw.rationale,
                }
                for vw in self.value_weights
            ],
            "active_fields": self.active_fields,
            "current_intention": self.current_intention,
            "trust_score": self.trust_score,
            "created_at": self.created_at.isoformat(),
            "updated_at": self.updated_at.isoformat(),
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "EDAState":
        """Rebuild EDAState from persisted JSON payload."""
        beliefs = {
            key: Belief(
                id=item["id"],
                proposition=item["proposition"],
                confidence=float(item["confidence"]),
                source=BeliefSource(item["source"]),
                norm_refs=item.get("norm_refs", []),
                timestamp=datetime.fromisoformat(item["timestamp"])
                if item.get("timestamp")
                else datetime.now(),
                requires_human_confirmation=item.get(
                    "requires_human_confirmation", False
                ),
            )
            for key, item in data.get("beliefs", {}).items()
        }
        norm_bindings = [
            NormBinding(
                norm_id=item["norm_id"],
                norm_type=NormType(item["norm_type"]),
                condition_met=bool(item.get("condition_met", False)),
                action_required=item.get("action_required", ""),
                action_prohibited=item.get("action_prohibited", []),
                sanction=item.get("sanction"),
                bound_at=datetime.fromisoformat(item["bound_at"])
                if item.get("bound_at")
                else datetime.now(),
            )
            for item in data.get("norm_bindings", [])
        ]
        value_weights = [
            ValueWeight(
                value_name=item["value_name"],
                weight=float(item["weight"]),
                hierarchy=int(item.get("hierarchy", 0)),
                rationale=item.get("rationale", ""),
            )
            for item in data.get("value_weights", [])
        ]
        return cls(
            agent_id=data["agent_id"],
            agent_role=data["agent_role"],
            beliefs=beliefs,
            norm_bindings=norm_bindings,
            value_weights=value_weights,
            active_fields=data.get("active_fields", []),
            current_intention=data.get("current_intention"),
            trust_score=float(data.get("trust_score", 0.8)),
            created_at=datetime.fromisoformat(data["created_at"])
            if data.get("created_at")
            else datetime.now(),
            updated_at=datetime.fromisoformat(data["updated_at"])
            if data.get("updated_at")
            else datetime.now(),
        )
