"""
Core types for Agentbyte framework.

This module defines fundamental data structures used throughout Agentbyte,
including tool execution results, orchestration responses, and event types.
"""

import time
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, ConfigDict, Field


class ToolResult(BaseModel):
    """
    Standardized result from tool execution.

    Provides consistent error handling and result formatting across all tools.
    This immutable structure ensures tool execution results are predictable
    and can be safely logged, serialized, or passed to LLMs.

    Attributes:
        success: Whether tool executed successfully
        result: Tool output data (can be None)
        error: Error message if execution failed
        metadata: Additional execution context (tool name, timing, exception type, etc.)

    Example:
        # Success case
        result = ToolResult(
            success=True,
            result="Weather in Paris: sunny",
            metadata={"tool_name": "get_weather", "execution_time": 0.234}
        )

        # Failure case
        result = ToolResult(
            success=False,
            result=None,
            error="Invalid location: 'Paris' not found",
            metadata={"tool_name": "get_weather", "exception_type": "ValueError"}
        )

    Note:
        - Immutable after creation (frozen=True) to prevent accidental modifications
        - Pydantic validation ensures all fields are properly typed
        - Metadata is extensible for custom tools to add their own context
    """

    success: bool = Field(..., description="Whether tool executed successfully")
    result: Any = Field(None, description="Tool output data")
    error: Optional[str] = Field(
        None, description="Error message if tool execution failed"
    )
    metadata: Dict[str, Any] = Field(
        default_factory=dict,
        description="Additional execution context (tool name, timing, exception info, etc.)",
    )

    model_config = ConfigDict(frozen=True)


class StopMessage(BaseModel):
    """
    Describes why and how orchestration stopped.

    Used by termination conditions to communicate stop reasons
    to the orchestrator and end users.

    Attributes:
        content: Human-readable stop reason
        source: Which termination condition triggered
        metadata: Additional context (e.g., message_count, token_count)

    Example:
        stop = StopMessage(
            content="Maximum messages reached (10/10)",
            source="MaxMessageTermination",
            metadata={"message_count": 10, "max_messages": 10}
        )
    """

    content: str = Field(..., description="Human-readable stop reason")
    source: str = Field(..., description="Which termination condition triggered")
    metadata: Dict[str, Any] = Field(
        default_factory=dict,
        description="Additional context (e.g., message_count, token_count)",
    )

    model_config = ConfigDict(frozen=True)


class OrchestrationResponse(BaseModel):
    """
    Final result from orchestration execution.

    Contains complete conversation history, aggregated usage statistics,
    and metadata about the orchestration run.

    Attributes:
        messages: Complete conversation history from all agents
        final_result: Summary extracted from last assistant message
        usage: Aggregated usage across all agent executions
        stop_message: Why orchestration ended
        pattern_metadata: Pattern-specific metrics

    Example:
        response = OrchestrationResponse(
            messages=[user_msg, agent1_msg, agent2_msg],
            final_result="Task completed successfully",
            usage=Usage(duration_ms=5000, llm_calls=3),
            stop_message=StopMessage(content="Done", source="TextMention"),
            pattern_metadata={"cycles_completed": 2}
        )

    Note:
        This type requires importing Message and Usage from other modules.
        To avoid circular imports, these are imported as TYPE_CHECKING only.
    """

    messages: List[Any] = Field(
        ..., description="Complete conversation history from all agents"
    )
    final_result: str = Field(
        ..., description="Summary extracted from last assistant message"
    )
    usage: Any = Field(..., description="Aggregated usage across all agent executions")
    stop_message: StopMessage = Field(..., description="Why orchestration ended")
    pattern_metadata: Dict[str, Any] = Field(
        default_factory=dict,
        description="Pattern-specific metrics (e.g., cycles_completed for RoundRobin)",
    )

    model_config = ConfigDict(frozen=False)


class OrchestrationEvent(BaseModel):
    """
    Base class for orchestration lifecycle events.

    Events are emitted during orchestration when verbose=True,
    providing observability into coordination decisions.

    Attributes:
        source: Event source (usually 'orchestrator')
        timestamp: Unix timestamp when event occurred
    """

    source: str = Field(
        default="orchestrator", description="Event source (usually 'orchestrator')"
    )
    timestamp: float = Field(
        default_factory=lambda: time.time(),
        description="Unix timestamp when event occurred",
    )

    model_config = ConfigDict(frozen=True)


class OrchestrationStartEvent(OrchestrationEvent):
    """
    Emitted when orchestration begins.

    Attributes:
        task: Initial task description
        pattern: Orchestration pattern name
    """

    task: str = Field(..., description="Initial task description")
    pattern: str = Field(..., description="Orchestration pattern name")


class OrchestrationCompleteEvent(OrchestrationEvent):
    """
    Emitted when orchestration ends.

    Attributes:
        result: Final result summary
        stop_reason: Why orchestration stopped
    """

    result: str = Field(..., description="Final result summary")
    stop_reason: str = Field(..., description="Why orchestration stopped")


class AgentSelectionEvent(OrchestrationEvent):
    """
    Emitted when an agent is selected for execution.

    Attributes:
        selected_agent: Name of selected agent
        selection_reason: Why this agent was chosen
    """

    selected_agent: str = Field(..., description="Name of selected agent")
    selection_reason: str = Field(
        ..., description="Why this agent was chosen (e.g., 'Iteration 3')"
    )


class AgentExecutionStartEvent(OrchestrationEvent):
    """
    Emitted when agent execution begins.

    Attributes:
        executing_agent: Name of executing agent
        context_size: Number of context items
    """

    executing_agent: str = Field(..., description="Name of executing agent")
    context_size: int = Field(
        ..., description="Number of context items (1 for string, N for list)"
    )


class AgentExecutionCompleteEvent(OrchestrationEvent):
    """
    Emitted when agent execution completes.

    Attributes:
        executing_agent: Name of executed agent
        success: Whether execution succeeded
        message_count: Number of messages produced by agent
    """

    executing_agent: str = Field(..., description="Name of executed agent")
    success: bool = Field(..., description="Whether execution succeeded")
    message_count: int = Field(..., description="Number of messages produced by agent")


__all__ = [
    "ToolResult",
    "StopMessage",
    "OrchestrationResponse",
    "OrchestrationEvent",
    "OrchestrationStartEvent",
    "OrchestrationCompleteEvent",
    "AgentSelectionEvent",
    "AgentExecutionStartEvent",
    "AgentExecutionCompleteEvent",
]
