"""
ASDP v1.0 — pack (intent) / unpack (world state) for Gateway
"""
from __future__ import annotations

from typing import Any
from pydantic import BaseModel, Field, field_validator


class ActionItem(BaseModel):
    type: str
    parameters: Any

    @field_validator('parameters')
    @classmethod
    def ensure_list(cls, v):
        if isinstance(v, (int, float, str)):
            return [v]
        return v


class ASDPIntent(BaseModel):
    """Proxy -> Server: intent submission"""
    agent_id: str
    action_queue: list[ActionItem] = Field(default_factory=list)
    cognitive_context: dict[str, Any] | None = None


class AgentSnapshot(BaseModel):
    id: str
    pos: list[float]
    hp: float
    status: str
    msg: str | None = None
    thought: str | None = None
    # display name and visual assets (optional)
    display_name: str | None = None
    primary_color: str | None = None
    model_type: str | None = None


class WorldEvent(BaseModel):
    from_: str = Field(alias="from")
    type: str
    content: str
    t: float | int
    # help: Hub sends on ask/answer for LLM to recognize and reply
    target: str | None = None
    help_id: str | None = None
    reply_to: str | None = None

    model_config = {"populate_by_name": True}


class Obstacle(BaseModel):
    id: str
    type: str = "circle"
    pos: list[float]
    r: float
    style: str = "rock"


class ASDPWorldState(BaseModel):
    """Server -> Proxy: world state broadcast (20Hz)"""
    t: float | int
    agents: list[AgentSnapshot] = Field(default_factory=list)
    world_events: list[WorldEvent] = Field(default_factory=list)
    obstacles: list[Obstacle] = Field(default_factory=list)
    # room-supported actions, synced to Agent/LLM for decisions
    supported_actions: list[str] = Field(default_factory=list)
    # gem game: 3 candidate positions, scores, remaining time
    gem_candidates: list[list[float]] | None = None
    gem_scores: dict[str, int] | None = None
    gem_game_remaining_ms: int | None = None
    gem_game_over: bool | None = None


def pack_intent(agent_id: str, action_queue: list[dict], cognitive_context: dict | None = None) -> str:
    intent = ASDPIntent(
        agent_id=agent_id,
        action_queue=[ActionItem(**a) for a in action_queue],
        cognitive_context=cognitive_context,
    )
    return intent.model_dump_json(by_alias=False)


def unpack_world_state(raw: str) -> ASDPWorldState | None:
    try:
        return ASDPWorldState.model_validate_json(raw)
    except Exception:
        return None
