"""Build _meta dict for MCP tool responses.

Per docs/INTERFACES.md Section E, every MCP tool response must include a _meta dict
with trace_id and instance_id. This module provides a helper to
construct this metadata from agent state.

Typical usage:
    from anima.shell.meta import build_meta

    meta = build_meta(agent_state)
    response = {"result": "ok", "_meta": meta}
"""

# @invar:allow shell_result: Pure dict builders for MCP responses

from typing import Any

from anima.core.schemas import AgentStateData


# @invar:allow shell_result: Pure dict builder for MCP response metadata
# @shell_orchestration: Helper for MCP response construction
def build_meta(state: AgentStateData) -> dict[str, Any]:
    """Build _meta dict for MCP tool responses.

    Per docs/INTERFACES.md Section E, _meta contains:
    - trace_id: Always present (end-to-end trace)
    - instance_id: Always present (agent instance)
    - persona_id: Optional (if PersonaSpec has it)

    Args:
        state: AgentStateData containing agent metadata.

    Returns:
        Dict with required _meta fields per docs/INTERFACES.md Section E.

    >>> from anima.core.schemas import AgentStateData, AgentState
    >>> state = AgentStateData(
    ...     instance_id="inst_abc",
    ...     trace_id="tr_123",
    ...     persona_name="test"
    ... )
    >>> meta = build_meta(state)
    >>> meta["trace_id"]
    'tr_123'
    >>> meta["instance_id"]
    'inst_abc'
    >>> "persona_id" in meta
    False

    >>> # With persona_id source from state.spec_id
    >>> state2 = AgentStateData(
    ...     instance_id="inst_uvw",
    ...     trace_id="tr_456",
    ...     persona_name="test",
    ...     spec_id="persona@abc123"
    ... )
    >>> meta2 = build_meta(state2)
    >>> meta2["persona_id"]
    'persona@abc123'

    >>> # spec_digest is not part of Meta and is omitted
    >>> state3 = AgentStateData(
    ...     instance_id="inst_xyz",
    ...     trace_id="tr_789",
    ...     persona_name="test",
    ...     spec_id="persona@def456",
    ...     spec_digest="sha256:abc123"
    ... )
    >>> meta3 = build_meta(state3)
    >>> meta3["persona_id"]
    'persona@def456'
    >>> "spec_digest" in meta3
    False
    """
    meta: dict[str, Any] = {
        "trace_id": state.trace_id,
        "instance_id": state.instance_id,
        "agent_id": state.instance_id,  # Backward compat alias
    }

    # Optional fields from docs/INTERFACES.md Section E
    if state.spec_id is not None:
        meta["persona_id"] = state.spec_id

    return meta


# @invar:allow shell_result: Pure dict builder for MCP error responses
# @shell_orchestration: Minimal _meta for error responses
def build_meta_from_instance_id(instance_id: str) -> dict[str, Any]:
    """Build minimal _meta dict when only instance_id is known (error cases).

    Used when an agent lookup fails but we still need to include _meta
    in the error response. Returns a minimal _meta with:
    - instance_id: The requested instance_id
    - trace_id: Empty string (unknown)

    Args:
        instance_id: The instance_id that was requested (may not exist).

    Returns:
        Dict with minimal _meta fields for error responses.

    >>> meta = build_meta_from_instance_id("inst_missing")
    >>> meta["instance_id"]
    'inst_missing'
    >>> meta["trace_id"]
    ''
    """
    return {
        "instance_id": instance_id,
        "agent_id": instance_id,  # Backward compat alias
        "trace_id": "",
    }


# Backward compatibility alias
build_meta_from_agent_id = build_meta_from_instance_id
