"""
Prompt Pattern Classes
Pattern definitions and substitution logic
FIXED: Added venv support to fallback pattern
"""

import re
import logging
from typing import Optional, List, Tuple
from dataclasses import dataclass

logger = logging.getLogger(__name__)


@dataclass
class PromptPattern:
    """Represents a prompt pattern with substitution variables"""
    pattern: str
    description: str

    def substitute(self, user: str, host: str) -> str:
        """
        Substitute variables in pattern

        Args:
            user: Username
            host: Hostname (can be IP or hostname)

        Returns:
            Pattern with variables substituted

        FIXED: Uses flexible pattern that matches any hostname/IP
        """
        result = self.pattern.replace("{user}", user)
        # Replace {host} with flexible pattern that matches hostname OR IP
        result = result.replace("{host}", r"[a-zA-Z0-9\-\.]+")
        return result


@dataclass
class PromptChangingCommand:
    """Command that changes the shell prompt"""
    command: str
    new_pattern: str
    description: str


class PromptPatternManager:
    """Manages prompt patterns and pattern-related operations"""

    def __init__(self, config: dict):
        """
        Initialize pattern manager

        Args:
            config: Configuration dictionary with prompt_detection section
        """
        self.config = config

        # Load prompt patterns
        patterns_config = config.get("prompt_detection", {}).get("patterns", [])
        self.patterns = [
            PromptPattern(pattern=p, description=f"Pattern: {p}")
            for p in patterns_config
        ]

        # Load prompt-changing commands
        pcc_config = config.get("prompt_detection", {}).get("prompt_changing_commands", [])
        self.prompt_changing_commands = [
            PromptChangingCommand(
                command=pcc["command"],
                new_pattern=pcc["new_pattern"],
                description=pcc.get("description", "")
            )
            for pcc in pcc_config
        ]

        # Settings
        self.background_pattern = config.get("prompt_detection", {}).get("background_command_pattern", r"&\s*$")

        self.user = None
        self.host = None

    def set_credentials(self, user: str, host: str):
        """Set user and host for pattern substitution"""
        self.user = user
        self.host = host

    def get_prompt_patterns(self) -> List[str]:
        """
        Get list of prompt patterns with substituted variables

        Returns:
            List of regex pattern strings
        """
        if not self.user or not self.host:
            logger.warning("User/host not set for prompt detection")
            return []

        return [
            pattern.substitute(self.user, self.host)
            for pattern in self.patterns
        ]

    def detect_prompt_in_line(self, line: str, prompt_pattern: str) -> Tuple[bool, str]:
        """
        Detect if line contains prompt pattern

        Args:
            line: Line to check
            prompt_pattern: Regex pattern to match

        Returns:
            (detected, reason) tuple
            - detected: True if prompt found, "verify" if suspicious, False otherwise
            - reason: Description of detection result
        """
        try:
            if not re.search(prompt_pattern, line):
                return False, "not_found"
        except re.error as e:
            logger.error(f"Invalid regex pattern '{prompt_pattern}': {e}")
            return False, "invalid_pattern"

        # CASE 1: Clean prompt (line is just the prompt)
        # Example: "user@host:~$"
        if line.strip() == prompt_pattern.strip() or re.fullmatch(prompt_pattern, line.strip()):
            return True, "clean_prompt"

        # Extract prompt match
        match = re.search(prompt_pattern, line)
        if not match:
            return False, "not_found"

        before = line[:match.start()]
        after = line[match.end():]

        # CASE 2: Prompt at start of line, nothing after
        # Example: "user@host:~$  \n"
        if not before and not after.strip():
            return True, "start_of_line"

        # CASE 3: Prompt at end of line, nothing after
        # Example: "some outputuser@host:~$"
        if not after.strip():
            # Check if there's non-whitespace before prompt
            if before and before.strip():
                return "verify", "suspicious_text_before"
            else:
                return True, "end_of_line"

        # CASE 4: Text after prompt - suspicious
        # Example: "user@host:~$ is the prompt"
        if after.strip():
            return "verify", "suspicious_text_after"

        return False, "unknown"

    def detect_prompt_changing_command(self, command: str) -> Optional[str]:
        """
        Check if command changes the prompt

        Args:
            command: Command to check

        Returns:
            New prompt pattern if command changes prompt, None otherwise
        """
        cmd_stripped = command.strip()

        for pcc in self.prompt_changing_commands:
            if cmd_stripped.startswith(pcc.command):
                # Substitute variables
                if self.user and self.host:
                    new_pattern = pcc.new_pattern.replace("{user}", self.user)
                    new_pattern = new_pattern.replace("{host}", r"[a-zA-Z0-9\-\.]+")
                    return new_pattern
                else:
                    return pcc.new_pattern

        return None

    def is_background_command(self, command: str) -> bool:
        """
        Check if command is backgrounded with &

        Args:
            command: Command to check

        Returns:
            True if command ends with &
        """
        return bool(re.search(self.background_pattern, command.strip()))

    def get_current_prompt(self) -> str:
        """
        Get the most likely current prompt pattern

        Returns:
            Regex pattern for current prompt
        """
        patterns = self.get_prompt_patterns()
        if patterns:
            # Return first (most common) pattern
            return patterns[0]
        else:
            # Fallback - flexible pattern that matches any user@host:path$ with optional venv prefix
            # FIXED: Added (\(.+\)\s+)? to support virtual environment prompts like (.venv) user@host:~$
            return r"(\(.+\)\s+)?[a-zA-Z0-9_]+@[a-zA-Z0-9\-\.]+:.*[$#]\s*$"
