"""Subagent orchestration pattern (Supervisor + parallel tools)."""

from __future__ import annotations

import logging
from dataclasses import dataclass
from enum import Enum
from typing import Any

from cyberbrain26.orchestration.subagent.interface import BaseSubagent
from cyberbrain26.orchestration.subagent.types import SubagentOutput

logger = logging.getLogger(__name__)


class SupervisorDecision(str, Enum):
    """Decision for which subagent to call next."""

    CONTINUE = "continue"
    FINISH = "finish"
    ERROR = "error"


@dataclass
class SubagentTool:
    """A subagent as a tool for the supervisor agent."""

    role: str
    spec: Any  # SubagentSpec

    def __call__(self, input_data: dict[str, Any]) -> SubagentOutput:
        """Execute the subagent tool.

        Note: This is a simplified representation. In a real implementation,
        this would be a proper function that can be called by the supervisor.
        """
        # This would be dynamically created based on the spec
        # For now, we just provide the structure
        return SubagentOutput(
            summary="Tool executed",
            confidence=0.8,
            requires_human_review=False,
        )


class SubagentPattern(BaseSubagent):
    """Subagent pattern: supervisor coordinates subagents as tools.

    This pattern implements the "subagent" pattern from LangChain where a
    main supervisor agent routes tasks to specialized subagents by calling them
    as tools. This provides context isolation, parallelization, and centralized
    control.

    Per LangChain best practices:
    - Main agent decides which subagent to invoke, what input to provide
    - Subagents return results to main agent, not directly to user
    - Parallel execution possible for independent domains
    - Centralized workflow control and error handling
    """

    def __init__(self, spec: Any) -> None:
        super().__init__(spec)
        self._subagents: list[SubagentTool] = []

    def add_subagent(self, subagent: SubagentTool) -> None:
        """Add a subagent to the supervisor's toolset."""
        self._subagents.append(subagent)

    async def invoke(self, input_data: dict[str, Any]) -> SubagentOutput:
        """Execute supervisor pattern: route to subagents based on task analysis.

        Args:
            input_data: Input to analyze and route

        Returns:
            Aggregated results from subagent executions
        """
        logger.debug(
            "Supervisor %s routing input: %s", self.spec.role, input_data,
        )

        # Analyze task to determine which subagent(s) to invoke
        relevant_subagents = self._select_subagents(input_data)

        # Execute subagents in parallel for independent domains
        results: list[SubagentOutput] = []
        for subagent in relevant_subagents:
            try:
                result = subagent(input_data)
                results.append(result)
            except Exception as e:
                logger.error("Subagent %s failed: %s", subagent.role, e, exc_info=True)
                results.append(
                    SubagentOutput(
                        summary=f"Subagent {subagent.role} failed: {e!s}",
                        confidence=0.0,
                        requires_human_review=True,
                        obstacles=[f"Subagent execution error: {e!s}"],
                    )
                )

        # Aggregate results from subagents
        return self._aggregate_results(input_data, results)

    def _select_subagents(self, input_data: dict[str, Any]) -> list[SubagentTool]:
        """Select relevant subagents based on task analysis."""
        # Simple heuristic: select all subagents for now
        # In practice, this would analyze input to determine which
        # subagent specialization is needed
        return self._subagents

    def _aggregate_results(
        self, input_data: dict[str, Any], results: list[SubagentOutput],
    ) -> SubagentOutput:
        """Aggregate results from multiple subagents."""
        if not results:
            return SubagentOutput(
                summary="No subagents were invoked",
                confidence=0.0,
                requires_human_review=True,
            )

        # Combine evidence from all subagents
        all_evidence = []
        for result in results:
            all_evidence.extend(result.evidence_refs)

        # Calculate average confidence
        avg_confidence = sum(r.confidence for r in results) / len(results)

        # Combine obstacles from all subagents
        all_obstacles = []
        for result in results:
            all_obstacles.extend(result.obstacles)

        return SubagentOutput(
            summary=f"Executed by {len(results)} subagent(s): "
            f"{', '.join(r.summary for r in results)}",
            evidence_refs=all_evidence,
            artifacts=[art for r in results for art in r.artifacts],
            confidence=avg_confidence,
            requires_human_review=any(r.requires_human_review for r in results),
            obstacles=all_obstacles,
        )