"""
Handoff Manager - Manage context handoffs between agents.

Provides:
- Context preparation for handoffs
- Work summary generation
- State transfer between agents
- Handoff history tracking
"""

import logging
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any, Callable, Optional

logger = logging.getLogger(__name__)


class HandoffReason(Enum):
    """Reasons for agent handoff."""

    CAPABILITY_MISMATCH = "capability_mismatch"  # Agent lacks required capability
    RATE_LIMITED = "rate_limited"  # Agent hit rate limits
    TASK_COMPLETE = "task_complete"  # Sub-task complete, hand to next
    ESCALATION = "escalation"  # Escalating to more capable agent
    SPECIALIZATION = "specialization"  # Handing to specialized agent
    FAILURE_RECOVERY = "failure_recovery"  # Recovering from failure
    USER_REQUESTED = "user_requested"  # User requested specific agent
    LOAD_BALANCING = "load_balancing"  # Distributing work


@dataclass
class HandoffContext:
    """Context transferred during agent handoff."""

    handoff_id: str
    from_agent: str
    to_agent: str
    reason: HandoffReason
    task_summary: str
    completed_work: list[str] = field(default_factory=list)
    remaining_work: list[str] = field(default_factory=list)
    shared_state: dict[str, Any] = field(default_factory=dict)
    files_modified: list[str] = field(default_factory=list)
    important_decisions: list[str] = field(default_factory=list)
    warnings: list[str] = field(default_factory=list)
    created_at: datetime = field(default_factory=datetime.now)
    metadata: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "handoff_id": self.handoff_id,
            "from_agent": self.from_agent,
            "to_agent": self.to_agent,
            "reason": self.reason.value,
            "task_summary": self.task_summary,
            "completed_work": self.completed_work,
            "remaining_work": self.remaining_work,
            "shared_state": self.shared_state,
            "files_modified": self.files_modified,
            "important_decisions": self.important_decisions,
            "warnings": self.warnings,
            "created_at": self.created_at.isoformat(),
            "metadata": self.metadata,
        }

    def to_prompt(self) -> str:
        """Generate prompt text for target agent."""
        lines = [
            f"## Handoff from {self.from_agent}",
            "",
            f"**Reason:** {self.reason.value.replace('_', ' ').title()}",
            "",
            "### Task Summary",
            self.task_summary,
            "",
        ]

        if self.completed_work:
            lines.append("### Completed Work")
            for item in self.completed_work:
                lines.append(f"- {item}")
            lines.append("")

        if self.remaining_work:
            lines.append("### Remaining Work")
            for item in self.remaining_work:
                lines.append(f"- {item}")
            lines.append("")

        if self.files_modified:
            lines.append("### Files Modified")
            for f in self.files_modified:
                lines.append(f"- {f}")
            lines.append("")

        if self.important_decisions:
            lines.append("### Important Decisions Made")
            for decision in self.important_decisions:
                lines.append(f"- {decision}")
            lines.append("")

        if self.warnings:
            lines.append("### Warnings")
            for warning in self.warnings:
                lines.append(f"- ⚠️ {warning}")
            lines.append("")

        return "\n".join(lines)


@dataclass
class HandoffResult:
    """Result of a handoff operation."""

    handoff_id: str
    success: bool
    from_agent: str
    to_agent: str
    context: HandoffContext
    error: Optional[str] = None
    executed_at: datetime = field(default_factory=datetime.now)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "handoff_id": self.handoff_id,
            "success": self.success,
            "from_agent": self.from_agent,
            "to_agent": self.to_agent,
            "context": self.context.to_dict(),
            "error": self.error,
            "executed_at": self.executed_at.isoformat(),
        }


class HandoffManager:
    """
    Manage context handoffs between agents.

    Enables seamless transfer of task context and state from one agent
    to another, maintaining continuity in multi-agent workflows.

    Inspired by Microsoft Multi-Agent Reference Architecture patterns.

    Example:
        manager = HandoffManager()

        # Prepare handoff
        context = await manager.prepare_handoff(
            from_agent="claude-code",
            to_agent="gemini-cli",
            reason=HandoffReason.RATE_LIMITED,
            task_summary="Implementing user auth",
            completed_work=["Created auth middleware", "Added login endpoint"],
            remaining_work=["Add password reset", "Write tests"],
        )

        # Execute handoff
        result = await manager.execute_handoff(context)
    """

    def __init__(self):
        """Initialize the handoff manager."""
        self._handoff_counter = 0
        self._history: list[HandoffResult] = []
        self._callbacks: list[Callable[[HandoffResult], None]] = []

    async def prepare_handoff(
        self,
        from_agent: str,
        to_agent: str,
        reason: HandoffReason,
        task_summary: str,
        completed_work: Optional[list[str]] = None,
        remaining_work: Optional[list[str]] = None,
        shared_state: Optional[dict[str, Any]] = None,
        files_modified: Optional[list[str]] = None,
        important_decisions: Optional[list[str]] = None,
        warnings: Optional[list[str]] = None,
        metadata: Optional[dict[str, Any]] = None,
    ) -> HandoffContext:
        """
        Prepare context for handoff.

        Args:
            from_agent: Source agent ID
            to_agent: Target agent ID
            reason: Reason for handoff
            task_summary: Summary of the task
            completed_work: List of completed items
            remaining_work: List of remaining items
            shared_state: State to transfer
            files_modified: List of modified files
            important_decisions: Key decisions made
            warnings: Warnings for target agent
            metadata: Additional metadata

        Returns:
            HandoffContext ready for execution
        """
        self._handoff_counter += 1
        handoff_id = f"handoff-{self._handoff_counter}"

        context = HandoffContext(
            handoff_id=handoff_id,
            from_agent=from_agent,
            to_agent=to_agent,
            reason=reason,
            task_summary=task_summary,
            completed_work=completed_work or [],
            remaining_work=remaining_work or [],
            shared_state=shared_state or {},
            files_modified=files_modified or [],
            important_decisions=important_decisions or [],
            warnings=warnings or [],
            metadata=metadata or {},
        )

        logger.info(
            f"Prepared handoff {handoff_id} from {from_agent} to {to_agent} "
            f"({reason.value})"
        )

        return context

    async def execute_handoff(
        self,
        context: HandoffContext,
        start_target_agent: Optional[Callable] = None,
    ) -> HandoffResult:
        """
        Execute the handoff to target agent.

        Args:
            context: Prepared handoff context
            start_target_agent: Optional callback to start target agent

        Returns:
            HandoffResult with success status
        """
        try:
            # Generate prompt for target agent
            handoff_prompt = context.to_prompt()

            # Start target agent if callback provided
            if start_target_agent:
                await start_target_agent(
                    agent_id=context.to_agent,
                    initial_prompt=handoff_prompt,
                    inherited_state=context.shared_state,
                )

            result = HandoffResult(
                handoff_id=context.handoff_id,
                success=True,
                from_agent=context.from_agent,
                to_agent=context.to_agent,
                context=context,
            )

            logger.info(f"Executed handoff {context.handoff_id} successfully")

        except Exception as e:
            result = HandoffResult(
                handoff_id=context.handoff_id,
                success=False,
                from_agent=context.from_agent,
                to_agent=context.to_agent,
                context=context,
                error=str(e),
            )

            logger.error(f"Handoff {context.handoff_id} failed: {e}")

        # Record and notify
        self._history.append(result)
        self._notify_callbacks(result)

        return result

    def on_handoff(self, callback: Callable[[HandoffResult], None]) -> None:
        """Register callback for handoff events."""
        self._callbacks.append(callback)

    def _notify_callbacks(self, result: HandoffResult) -> None:
        """Notify all registered callbacks."""
        for callback in self._callbacks:
            try:
                callback(result)
            except Exception as e:
                logger.error(f"Error in handoff callback: {e}")

    def get_history(
        self,
        agent_id: Optional[str] = None,
        success_only: bool = False,
        limit: int = 100,
    ) -> list[HandoffResult]:
        """
        Get handoff history.

        Args:
            agent_id: Filter by agent (as source or target)
            success_only: Only return successful handoffs
            limit: Maximum results

        Returns:
            List of handoff results
        """
        results = self._history

        if agent_id:
            results = [
                r for r in results
                if r.from_agent == agent_id or r.to_agent == agent_id
            ]

        if success_only:
            results = [r for r in results if r.success]

        return results[-limit:]

    def get_stats(self) -> dict[str, Any]:
        """Get handoff statistics."""
        total = len(self._history)
        successful = sum(1 for r in self._history if r.success)

        by_reason: dict[str, int] = {}
        for result in self._history:
            reason = result.context.reason.value
            by_reason[reason] = by_reason.get(reason, 0) + 1

        return {
            "total_handoffs": total,
            "successful": successful,
            "failed": total - successful,
            "success_rate": successful / total if total > 0 else 0,
            "by_reason": by_reason,
        }


# Module-level instance
_manager: Optional[HandoffManager] = None


def get_handoff_manager() -> HandoffManager:
    """Get or create the global handoff manager."""
    global _manager
    if _manager is None:
        _manager = HandoffManager()
    return _manager


def set_handoff_manager(manager: Optional[HandoffManager]) -> None:
    """Set the global handoff manager."""
    global _manager
    _manager = manager
