"""
Base pattern definitions for orchestration patterns.

This module provides the foundation classes for all orchestration patterns,
including configuration, results, and the abstract base pattern interface.
"""

from abc import ABC, abstractmethod
from typing import Any, Dict, Optional
from pydantic import BaseModel, Field
from enum import Enum


class PatternType(str, Enum):
    """
    Enumeration of available orchestration pattern types.

    Each pattern type represents a distinct approach to agentic AI orchestration:
    - REFLECTION: Iterative self-critique and refinement
    - TOOL_USE: External tool integration and execution
    - REACT: Reasoning and acting with thought traces
    - PLANNING: Task decomposition and sequential execution
    - MULTI_AGENT: Collaborative multi-agent problem solving
    """

    REFLECTION = "reflection"
    TOOL_USE = "tool_use"
    REACT = "react"
    PLANNING = "planning"
    MULTI_AGENT = "multi_agent"


class PatternConfig(BaseModel):
    """
    Configuration model for orchestration patterns.

    This Pydantic model defines the configuration parameters that control
    pattern execution behavior, including iteration limits, timeouts, and
    custom metadata.

    :param name: str - Unique identifier for the pattern instance.
    :param pattern_type: PatternType - The type of orchestration pattern.
    :param max_iterations: int - Maximum number of iterations allowed (minimum 1).
    :param timeout: Optional[float] - Execution timeout in seconds. None means no timeout.
    :param verbose: bool - Enable detailed logging output. Defaults to False.
    :param metadata: Dict[str, Any] - Custom metadata for pattern-specific configuration.
    """

    name: str = Field(..., description="Pattern name")
    pattern_type: PatternType = Field(..., description="Type of orchestration pattern")
    max_iterations: int = Field(10, ge=1, description="Maximum iterations")
    timeout: Optional[float] = Field(None, ge=0.0, description="Timeout in seconds")
    verbose: bool = Field(False, description="Enable verbose output")
    metadata: Dict[str, Any] = Field(default_factory=dict)


class PatternResult(BaseModel):
    """
    Result model for pattern execution outcomes.

    This Pydantic model encapsulates the results of pattern execution,
    including success status, output data, iteration count, errors, and
    execution metadata.

    :param success: bool - Whether the pattern execution succeeded.
    :param result: Any - The final output or answer from pattern execution.
    :param iterations: int - Number of iterations executed (minimum 0).
    :param error: Optional[str] - Error message if execution failed. None on success.
    :param metadata: Dict[str, Any] - Additional execution metadata (e.g., intermediate results, timing).
    """

    success: bool = Field(..., description="Whether pattern execution succeeded")
    result: Any = Field(None, description="Pattern execution result")
    iterations: int = Field(0, ge=0, description="Number of iterations executed")
    error: Optional[str] = Field(None, description="Error message if failed")
    metadata: Dict[str, Any] = Field(default_factory=dict)


class BasePattern(ABC):
    """
    Abstract base class for all orchestration patterns.

    This class defines the interface that all orchestration patterns must implement,
    including the core execute() and step() methods. It provides common functionality
    for iteration tracking and state management.

    Subclasses must implement:
    - execute(): Main entry point for pattern execution
    - step(): Single iteration/step logic

    The base class handles iteration counting and provides lifecycle hooks for
    pattern initialization and reset.
    """

    def __init__(self, config: PatternConfig):
        """
        Initialize the base pattern with configuration.

        :param config: PatternConfig - Configuration for this pattern instance.
        """
        self.config = config
        self.name = config.name
        self.pattern_type = config.pattern_type
        self._iteration_count = 0

    @abstractmethod
    async def execute(self, task: str, context: Optional[Dict[str, Any]] = None) -> PatternResult:
        """
        Execute the orchestration pattern on the given task.

        This is the main entry point for pattern execution. Subclasses must
        implement this method to define their specific orchestration logic.

        :param task: str - The task or question to execute.
        :param context: Optional[Dict[str, Any]] - Additional context for execution.
        :return: PatternResult - Execution results including success status and output.
        """
        pass

    @abstractmethod
    async def step(self, state: Dict[str, Any]) -> Dict[str, Any]:
        """
        Execute a single iteration step of the pattern.

        This method defines the logic for one iteration of the pattern's execution
        loop. Subclasses implement this to define step-level behavior.

        :param state: Dict[str, Any] - Current state including iteration count, history, etc.
        :return: Dict[str, Any] - Step results and updated state information.
        """
        pass

    def reset(self) -> None:
        """
        Reset the pattern state for a new execution.

        Clears iteration count and any other stateful information to prepare
        for a fresh pattern execution.
        """
        self._iteration_count = 0

    def increment_iteration(self) -> int:
        """
        Increment the iteration counter and return the new count.

        :return: int - The new iteration count after incrementing.
        """
        self._iteration_count += 1
        return self._iteration_count

    @property
    def current_iteration(self) -> int:
        """
        Get the current iteration count.

        :return: int - Current iteration number (0-indexed).
        """
        return self._iteration_count

    def __repr__(self) -> str:
        return f"<{self.__class__.__name__}(name='{self.name}', type='{self.pattern_type.value}')>"
