"""Defines agent configuration types (the "Blueprint" dimension).

This module contains types for defining agent behavior, including model
selection, system prompts, tool configurations, execution parameters, and
lifecycle hooks for orchestrating tool execution at critical points.
Agents in Xulcan are data (JSON configurations), not code (classes).
"""
from enum import Enum
from typing import List, Dict, Optional, Any
from pydantic import Field, field_validator

from xulcan.core.primitives import (
    CanonicalRecord,
    MachineID,
    ContextKey,
    SafePayload
)


# ═══════════════════════════════════════════════════════════════════════════
# AGENT CONFIGURATION TYPES
# ═══════════════════════════════════════════════════════════════════════════

class AgentToolConfig(CanonicalRecord):
    """Configuration for a single tool available to an agent.
    
    Tools can be enabled/disabled without removing them from the configuration.
    
    Attributes:
        name: The tool identifier (must match a registered tool).
        enabled: Whether this tool is currently available to the agent.
    
    Example:
        >>> tool = AgentToolConfig(name="web_search", enabled=True)
        >>> disabled_tool = AgentToolConfig(name="file_write", enabled=False)
    """
    name: MachineID = Field(
        description="Tool identifier (must match a registered tool)"
    )
    
    enabled: bool = Field(
        default=True,
        description="Whether this tool is available to the agent"
    )

    exposed: bool = Field(
        default=True,
        description="If True, the LLM can see and use this tool. If False, only Lifecycle hooks can use it."
    )


class LifecycleHook(CanonicalRecord):
    """
    Defines a tool execution within a lifecycle stage (Start, Finish, Error).
    
    This enables "Programmable Agents" by allowing tools to read from and
    write to the agent's dynamic context variables.
    
    Attributes:
        tool: The identifier of the tool to execute (must be enabled).
        
        arguments: Static arguments (hardcoded values).
            Example: {"limit": 5, "temperature": 0.0}
            
        arguments_map: Dynamic mapping from State Variables -> Tool Arguments.
            Key is the tool argument name. Value is the variable name in State.
            Example: {"query": "user_input"} -> assigns state['user_input'] to tool(query=...)
            
        output_variable: The name of the State Variable where the result will be stored.
            If None, the result is ignored (fire-and-forget).
            Example: "rag_context" -> state['rag_context'] = tool_result
    """
    tool: MachineID = Field(
        description="The identifier of the tool to execute"
    )
    
    arguments: SafePayload = Field(
        default_factory=dict,
        description="Static arguments pre-bound to this execution (JSON-serializable, depth-bounded)"
    )
    
    arguments_map: Dict[ContextKey, ContextKey] = Field(
        default_factory=dict,
        description="Map tool arguments to state variables (e.g. {'query': 'user_input'})"
    )
    
    output_variable: Optional[ContextKey] = Field(
        default=None,
        description="Name of the state variable to store the tool output"
    )


class LifecycleConfig(CanonicalRecord):
    """Configuration for lifecycle hooks that execute tools at critical points.
    
    Lifecycle hooks enable patterns like RAG (Retrieval Augmented Generation),
    context injection, cleanup operations, and error handling without polluting
    the core agent logic with "magic" configurations.
    
    All hooks are lists of tool names that the Kernel will invoke sequentially
    at the specified lifecycle stage. Tools must be registered and enabled in
    the agent's tools list.
    
    Attributes:
        on_start: Tools to execute before the main agent loop begins.
            Use cases: RAG retrieval, profile loading, context injection,
            workspace initialization.
        on_finish: Tools to execute after successful agent completion.
            Use cases: saving conversation summaries, updating databases,
            sending completion notifications, cleanup operations.
        on_error: Tools to execute if the agent encounters a fatal error.
            Use cases: error logging, alerting systems, rollback operations,
            sending failure notifications.
    
    Example:
        >>> lifecycle = LifecycleConfig(
        ...     on_start=["rag_retriever", "load_user_profile"],
        ...     on_finish=["save_summary", "update_metrics"],
        ...     on_error=["send_alert", "rollback_changes"]
        ... )
    
    Design Notes:
        - Hook execution is sequential within each stage
        - Hooks are optional; empty lists mean no execution
        - The Kernel is responsible for validating tool existence
        - Hook failures should be handled gracefully by the Kernel
    """
    on_start: List[LifecycleHook] = Field(
        default_factory=list,
        description="Tool names to execute before the main agent loop"
    )
    
    on_finish: List[LifecycleHook] = Field(
        default_factory=list,
        description="Tool names to execute after successful completion"
    )
    
    on_error: List[LifecycleHook] = Field(
        default_factory=list,
        description="Tool names to execute if the agent encounters an error"
    )
