"""Monitor agent panes for completion via MD5 hashing."""

import asyncio
import hashlib
import logging
from typing import Callable, Dict, Awaitable
from dataclasses import dataclass, field

logger = logging.getLogger(__name__)


@dataclass
class AgentState:
    """Tracks activity state for a single agent."""

    name: str
    last_hash: str = ""
    idle_count: int = 0


class ActivityMonitor:
    """Monitor agent panes for completion via MD5 hashing.

    Polls tmux panes at regular intervals and computes MD5 hash of content.
    When content remains unchanged for a threshold number of checks,
    the agent is considered complete.
    """

    def __init__(
        self,
        orchestrator,
        on_agent_complete: Callable[[str, str, str], Awaitable[None]],
        poll_interval: int = 2,
        idle_threshold: int = 3,
        capture_lines: int = 500,
    ):
        """Initialize activity monitor.

        Args:
            orchestrator: AgentOrchestrator instance for capturing output
            on_agent_complete: Async callback(name, duration, output) when agent completes
            poll_interval: Seconds between polls
            idle_threshold: Number of unchanged polls before considering done
            capture_lines: Lines to capture when agent completes
        """
        self.orchestrator = orchestrator
        self.on_agent_complete = on_agent_complete
        self.poll_interval = poll_interval
        self.idle_threshold = idle_threshold
        self.capture_lines = capture_lines

        self.tracked: Dict[str, AgentState] = {}
        self._running = False
        self._task = None

    def track(self, name: str) -> None:
        """Start tracking an agent.

        Args:
            name: Agent name to track
        """
        if name not in self.tracked:
            self.tracked[name] = AgentState(name=name)
            logger.debug(f"Now tracking agent: {name}")

    def untrack(self, name: str) -> None:
        """Stop tracking an agent.

        Args:
            name: Agent name to stop tracking
        """
        if name in self.tracked:
            del self.tracked[name]
            logger.debug(f"Stopped tracking agent: {name}")

    def is_tracking(self, name: str) -> bool:
        """Check if agent is being tracked.

        Args:
            name: Agent name

        Returns:
            True if agent is tracked
        """
        return name in self.tracked

    async def start(self) -> None:
        """Start monitoring loop."""
        self._running = True
        logger.info(
            f"Activity monitor started (poll={self.poll_interval}s, "
            f"threshold={self.idle_threshold})"
        )

        while self._running:
            try:
                await self._check_agents()
            except Exception as e:
                logger.error(f"Error in activity monitor: {e}")

            await asyncio.sleep(self.poll_interval)

    async def stop(self) -> None:
        """Stop monitoring loop."""
        self._running = False
        logger.info("Activity monitor stopped")

    async def _check_agents(self) -> None:
        """Check all tracked agents for completion."""
        if not self.tracked:
            return

        completed = []

        for name, state in list(self.tracked.items()):
            try:
                # Capture current pane content
                content = self.orchestrator.capture_output(name, self.capture_lines)

                if not content:
                    # Session might be gone
                    continue

                current_hash = hashlib.md5(content.encode()).hexdigest()

                if current_hash == state.last_hash:
                    # No change - increment idle count
                    state.idle_count += 1
                    logger.debug(
                        f"Agent {name} idle count: {state.idle_count}/{self.idle_threshold}"
                    )

                    if state.idle_count >= self.idle_threshold:
                        # Agent is done
                        completed.append((name, content))
                else:
                    # Content changed - reset idle count
                    if state.idle_count > 0:
                        logger.debug(f"Agent {name} activity detected, resetting idle count")
                    state.idle_count = 0
                    state.last_hash = current_hash

            except Exception as e:
                logger.error(f"Error checking agent {name}: {e}")

        # Notify completions
        for name, content in completed:
            agent = self.orchestrator.get_agent(name)
            duration = agent.duration if agent else "?"

            logger.info(f"Agent {name} completed @ {duration}")

            # Remove from tracking before callback to prevent re-detection
            self.untrack(name)

            try:
                await self.on_agent_complete(name, duration, content)
            except Exception as e:
                logger.error(f"Error in completion callback for {name}: {e}")

    def get_tracked_agents(self) -> list:
        """Get list of currently tracked agent names.

        Returns:
            List of agent names
        """
        return list(self.tracked.keys())

    def reset_agent_state(self, name: str) -> None:
        """Reset idle state for an agent.

        Useful when sending a message to an agent that should restart
        activity monitoring.

        Args:
            name: Agent name
        """
        if name in self.tracked:
            self.tracked[name].idle_count = 0
            self.tracked[name].last_hash = ""
            logger.debug(f"Reset activity state for agent: {name}")
