"""
Interaction Detector - Detect when CLI agents are waiting for user input.

Provides:
- Process monitoring for CLI agents
- Terminal state detection
- Input prompt classification
- Real-time waiting state detection
"""

import asyncio
import logging
import os
import re
import subprocess
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any, Callable, Optional

from ..tracking import (
    get_all_readers,
    CLIStateReader,
    WaitingState,
)

logger = logging.getLogger(__name__)


class InteractionType(Enum):
    """Types of user interactions CLI might request."""

    APPROVAL = "approval"  # Needs yes/no approval
    CLARIFICATION = "clarification"  # Needs more info
    TOOL_AUTHORIZATION = "tool_authorization"  # Needs tool auth
    FILE_PERMISSION = "file_permission"  # Needs file access
    COMMAND_CONFIRMATION = "command_confirmation"  # Needs command confirm
    CONTINUE_PROMPT = "continue_prompt"  # Press enter to continue
    CUSTOM_INPUT = "custom_input"  # Free-form input needed
    UNKNOWN = "unknown"


class RiskLevel(Enum):
    """Risk level for auto-responding to interactions."""

    LOW = "low"  # Safe to auto-respond
    MEDIUM = "medium"  # May need review
    HIGH = "high"  # Should not auto-respond
    CRITICAL = "critical"  # Must not auto-respond


@dataclass
class DetectedInteraction:
    """A detected interaction request from a CLI agent."""

    agent_id: str
    agent_type: str
    interaction_type: InteractionType
    prompt_text: str
    risk_level: RiskLevel
    suggested_response: Optional[str] = None
    detected_at: datetime = field(default_factory=datetime.now)
    context: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "agent_id": self.agent_id,
            "agent_type": self.agent_type,
            "interaction_type": self.interaction_type.value,
            "prompt_text": self.prompt_text,
            "risk_level": self.risk_level.value,
            "suggested_response": self.suggested_response,
            "detected_at": self.detected_at.isoformat(),
            "context": self.context,
        }


# Common prompt patterns for detection
APPROVAL_PATTERNS = [
    r"(?i)proceed\s*\?\s*\[?y/n\]?",
    r"(?i)continue\s*\?\s*\[?y/n\]?",
    r"(?i)do you want to\s+.+\?\s*\[?y/n\]?",
    r"(?i)allow\s+.+\?\s*\[?y/n\]?",
    r"(?i)confirm\s*\?",
    r"(?i)are you sure\s*\?",
]

TOOL_PATTERNS = [
    r"(?i)allow (bash|terminal|shell|command)",
    r"(?i)run (command|script)",
    r"(?i)execute\s+.+\?",
    r"(?i)tool use:\s*",
]

FILE_PATTERNS = [
    r"(?i)create (file|directory)",
    r"(?i)modify (file|directory)",
    r"(?i)delete (file|directory)",
    r"(?i)overwrite\s+.+\?",
    r"(?i)write to\s+.+\?",
]

DANGEROUS_PATTERNS = [
    r"(?i)rm\s+-rf",
    r"(?i)delete\s+all",
    r"(?i)drop\s+(table|database)",
    r"(?i)terraform\s+destroy",
    r"(?i)git\s+push\s+--force",
    r"(?i)sudo\s+",
    r"(?i)production",
]


class InteractionDetector:
    """
    Detect and classify CLI interaction requests.

    Monitors CLI agents for prompts that require user input
    and classifies them by type and risk level.

    Example:
        detector = InteractionDetector()

        # Check for pending interactions
        interactions = detector.check_all_agents()

        # Get interactions for specific agent
        interaction = detector.check_agent("claude-code")
        if interaction:
            print(f"Waiting for: {interaction.interaction_type}")
    """

    def __init__(
        self,
        readers: Optional[dict[str, CLIStateReader]] = None,
    ) -> None:
        """
        Initialize the interaction detector.

        Args:
            readers: Custom CLI state readers
        """
        self._readers = readers or get_all_readers()
        self._callbacks: list[Callable[[DetectedInteraction], None]] = []
        self._running = False
        self._last_interactions: dict[str, DetectedInteraction] = {}

    def register_reader(self, agent_id: str, reader: CLIStateReader) -> None:
        """Register a custom reader."""
        self._readers[agent_id] = reader

    def on_interaction(
        self,
        callback: Callable[[DetectedInteraction], None],
    ) -> None:
        """Register callback for detected interactions."""
        self._callbacks.append(callback)

    def check_agent(self, agent_id: str) -> Optional[DetectedInteraction]:
        """
        Check if a specific agent is waiting for input.

        Args:
            agent_id: Agent identifier

        Returns:
            DetectedInteraction if waiting, None otherwise
        """
        reader = self._readers.get(agent_id)
        if not reader:
            return None

        try:
            snapshot = reader.get_snapshot(agent_id)

            if not snapshot.session or not snapshot.session.waiting_for_input:
                return None

            prompt_text = snapshot.session.input_prompt or ""

            # Classify the interaction
            interaction_type = self._classify_interaction(prompt_text)
            risk_level = self._assess_risk(prompt_text, interaction_type)
            suggested_response = self._suggest_response(prompt_text, interaction_type)

            interaction = DetectedInteraction(
                agent_id=agent_id,
                agent_type=snapshot.agent_type,
                interaction_type=interaction_type,
                prompt_text=prompt_text,
                risk_level=risk_level,
                suggested_response=suggested_response,
                context={
                    "session_id": snapshot.session.session_id,
                    "waiting_state": snapshot.session.waiting_state.value,
                },
            )

            self._last_interactions[agent_id] = interaction
            return interaction

        except Exception as e:
            logger.warning(f"Error checking agent {agent_id}: {e}")
            return None

    def check_all_agents(self) -> list[DetectedInteraction]:
        """
        Check all agents for pending interactions.

        Returns:
            List of detected interactions
        """
        interactions = []
        for agent_id in self._readers.keys():
            interaction = self.check_agent(agent_id)
            if interaction:
                interactions.append(interaction)
        return interactions

    def _classify_interaction(self, prompt_text: str) -> InteractionType:
        """Classify the type of interaction."""
        # Check for approval patterns
        for pattern in APPROVAL_PATTERNS:
            if re.search(pattern, prompt_text):
                return InteractionType.APPROVAL

        # Check for tool authorization
        for pattern in TOOL_PATTERNS:
            if re.search(pattern, prompt_text):
                return InteractionType.TOOL_AUTHORIZATION

        # Check for file permissions
        for pattern in FILE_PATTERNS:
            if re.search(pattern, prompt_text):
                return InteractionType.FILE_PERMISSION

        # Check for command confirmation
        if re.search(r"(?i)run|execute|command", prompt_text):
            return InteractionType.COMMAND_CONFIRMATION

        # Check for continue prompt
        if re.search(r"(?i)press (enter|return)|continue", prompt_text):
            return InteractionType.CONTINUE_PROMPT

        return InteractionType.UNKNOWN

    def _assess_risk(
        self,
        prompt_text: str,
        interaction_type: InteractionType,
    ) -> RiskLevel:
        """Assess risk level for auto-response."""
        # Check for dangerous patterns
        for pattern in DANGEROUS_PATTERNS:
            if re.search(pattern, prompt_text):
                return RiskLevel.CRITICAL

        # Default risk by interaction type
        type_risks = {
            InteractionType.CONTINUE_PROMPT: RiskLevel.LOW,
            InteractionType.APPROVAL: RiskLevel.MEDIUM,
            InteractionType.CLARIFICATION: RiskLevel.MEDIUM,
            InteractionType.FILE_PERMISSION: RiskLevel.MEDIUM,
            InteractionType.TOOL_AUTHORIZATION: RiskLevel.HIGH,
            InteractionType.COMMAND_CONFIRMATION: RiskLevel.HIGH,
            InteractionType.CUSTOM_INPUT: RiskLevel.HIGH,
            InteractionType.UNKNOWN: RiskLevel.HIGH,
        }

        return type_risks.get(interaction_type, RiskLevel.HIGH)

    def _suggest_response(
        self,
        prompt_text: str,
        interaction_type: InteractionType,
    ) -> Optional[str]:
        """Suggest a response for low-risk interactions."""
        # Only suggest for low-risk interactions
        if interaction_type == InteractionType.CONTINUE_PROMPT:
            return ""  # Press enter

        if interaction_type == InteractionType.APPROVAL:
            # Only suggest yes for safe operations
            if not any(re.search(p, prompt_text) for p in DANGEROUS_PATTERNS):
                return "y"

        return None

    def get_last_interaction(self, agent_id: str) -> Optional[DetectedInteraction]:
        """Get the last detected interaction for an agent."""
        return self._last_interactions.get(agent_id)

    async def start_monitoring(self, interval_seconds: int = 5) -> None:
        """
        Start background monitoring loop.

        Args:
            interval_seconds: Check interval
        """
        self._running = True
        logger.info(f"Starting interaction monitoring (interval: {interval_seconds}s)")

        while self._running:
            try:
                interactions = self.check_all_agents()
                for interaction in interactions:
                    self._fire_callbacks(interaction)
            except Exception as e:
                logger.error(f"Error in monitoring loop: {e}")

            await asyncio.sleep(interval_seconds)

    def stop_monitoring(self) -> None:
        """Stop the monitoring loop."""
        self._running = False
        logger.info("Stopping interaction monitoring")

    def _fire_callbacks(self, interaction: DetectedInteraction) -> None:
        """Fire callbacks for a detected interaction."""
        for callback in self._callbacks:
            try:
                callback(interaction)
            except Exception as e:
                logger.error(f"Error in interaction callback: {e}")


def check_process_for_input(pid: int) -> bool:
    """
    Check if a process is waiting for stdin.

    Args:
        pid: Process ID

    Returns:
        True if waiting for input
    """
    try:
        # Check /proc on Linux
        proc_fd = f"/proc/{pid}/fd/0"
        if os.path.exists(proc_fd):
            # Check if stdin is a terminal and readable
            stat = os.stat(proc_fd)
            return True
    except (OSError, IOError):
        pass

    return False


# Module-level detector instance
_detector: Optional[InteractionDetector] = None


def get_interaction_detector() -> InteractionDetector:
    """Get or create the global interaction detector."""
    global _detector
    if _detector is None:
        _detector = InteractionDetector()
    return _detector


def set_interaction_detector(detector: Optional[InteractionDetector]) -> None:
    """Set the global interaction detector."""
    global _detector
    _detector = detector
