"""
REPL Configuration and State Management

Provides configurable settings and state tracking for the Native REPL:
- REPLConfig: Configuration dataclass for customizable behavior
- REPLState: Runtime state tracking
- InputType: Classification of user input
- ProcessedInput: Preprocessed input with metadata

Examples:
    # Create custom config
    config = REPLConfig(
        model="gpt-4o",
        max_cost=10.0,
        stream_responses=True,
    )

    # Track state
    state = REPLState()
    state.current_agent = "plan"
"""

from dataclasses import dataclass, field
from enum import Enum, auto
from typing import Any, Optional

from groknroll.tui.session import Session


class InputType(Enum):
    """Classification of user input types"""

    NATURAL_LANGUAGE = auto()  # Regular text prompts to LLM
    SLASH_COMMAND = auto()  # /help, /save, /agent, etc.
    SHELL_COMMAND = auto()  # !ls, !git status, etc.
    FILE_REFERENCE = auto()  # @filename references


@dataclass
class ProcessedInput:
    """
    Preprocessed user input with metadata

    Attributes:
        original: The original unmodified input string
        processed: The processed/expanded input string
        input_type: Classification of the input
        file_references: List of file paths referenced with @
        metadata: Additional metadata about the input
    """

    original: str
    processed: str
    input_type: InputType
    file_references: list[str] = field(default_factory=list)
    metadata: dict[str, Any] = field(default_factory=dict)

    @property
    def is_command(self) -> bool:
        """Check if input is a command (slash or shell)"""
        return self.input_type in (InputType.SLASH_COMMAND, InputType.SHELL_COMMAND)

    @property
    def has_file_references(self) -> bool:
        """Check if input contains file references"""
        return len(self.file_references) > 0


@dataclass
class REPLConfig:
    """
    Configuration for the Native REPL

    All settings can be customized at initialization or runtime.

    Attributes:
        model: LLM model identifier (default: gpt-4o-mini)
        max_cost: Maximum cost limit in dollars (default: 5.0)
        stream_responses: Enable streaming responses (default: True)
        auto_save: Enable automatic session saving (default: True)
        auto_save_interval: Seconds between auto-saves (default: 60)
        default_agent: Default agent to use (default: build)
        history_limit: Maximum conversation history entries (default: 100)
        show_tokens: Show token usage in responses (default: False)
        show_cost: Show cost information (default: False)
        timeout: Default timeout for operations in seconds (default: 300)
        welcome_message: Custom welcome message (default: None)
        fsd_mode: FSD Mode - skip ALL permission checks (default: False)

    Example:
        config = REPLConfig(
            model="gpt-4o",
            max_cost=10.0,
            stream_responses=True,
            default_agent="plan",
        )
    """

    model: str = "gpt-4o-mini"
    max_cost: float = 5.0
    stream_responses: bool = True
    auto_save: bool = True
    auto_save_interval: int = 60
    default_agent: str = "build"
    history_limit: int = 100
    show_tokens: bool = False
    show_cost: bool = False
    timeout: int = 300
    welcome_message: Optional[str] = None
    fsd_mode: bool = False  # FSD Mode: skip ALL permission checks

    def validate(self) -> list[str]:
        """
        Validate configuration values

        Returns:
            List of validation error messages (empty if valid)
        """
        errors = []

        if self.max_cost <= 0:
            errors.append("max_cost must be positive")

        if self.auto_save_interval < 10:
            errors.append("auto_save_interval must be at least 10 seconds")

        if self.history_limit < 1:
            errors.append("history_limit must be at least 1")

        if self.timeout < 1:
            errors.append("timeout must be at least 1 second")

        if self.default_agent not in ("build", "plan", "oracle"):
            errors.append("default_agent must be build, plan, or oracle")

        return errors

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary"""
        return {
            "model": self.model,
            "max_cost": self.max_cost,
            "stream_responses": self.stream_responses,
            "auto_save": self.auto_save,
            "auto_save_interval": self.auto_save_interval,
            "default_agent": self.default_agent,
            "history_limit": self.history_limit,
            "show_tokens": self.show_tokens,
            "show_cost": self.show_cost,
            "timeout": self.timeout,
            "welcome_message": self.welcome_message,
            "fsd_mode": self.fsd_mode,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "REPLConfig":
        """Create from dictionary"""
        return cls(
            model=data.get("model", "gpt-4o-mini"),
            max_cost=data.get("max_cost", 5.0),
            stream_responses=data.get("stream_responses", True),
            auto_save=data.get("auto_save", True),
            auto_save_interval=data.get("auto_save_interval", 60),
            default_agent=data.get("default_agent", "build"),
            history_limit=data.get("history_limit", 100),
            show_tokens=data.get("show_tokens", False),
            show_cost=data.get("show_cost", False),
            timeout=data.get("timeout", 300),
            welcome_message=data.get("welcome_message"),
            fsd_mode=data.get("fsd_mode", False),
        )


@dataclass
class REPLState:
    """
    Runtime state for the Native REPL

    Tracks the current state of the REPL session including
    running status, current agent, and conversation history.

    Attributes:
        running: Whether the REPL is currently running
        current_agent: Name of the currently active agent
        session: Current session object (for persistence)
        conversation_history: List of conversation messages
        total_cost: Total cost incurred this session
        total_tokens: Total tokens used this session
        turn_count: Number of conversation turns

    Example:
        state = REPLState()
        state.running = True
        state.current_agent = "plan"
    """

    running: bool = True
    current_agent: str = "build"
    session: Optional[Session] = None
    conversation_history: list[dict[str, Any]] = field(default_factory=list)
    total_cost: float = 0.0
    total_tokens: int = 0
    turn_count: int = 0

    def add_message(self, role: str, content: str, **metadata: Any) -> None:
        """
        Add a message to conversation history

        Args:
            role: Message role (user, assistant, system)
            content: Message content
            **metadata: Additional metadata
        """
        message = {
            "role": role,
            "content": content,
            **metadata,
        }
        self.conversation_history.append(message)

        # Update turn count for user messages
        if role == "user":
            self.turn_count += 1

    def get_messages(self, limit: Optional[int] = None) -> list[dict[str, Any]]:
        """
        Get conversation history

        Args:
            limit: Maximum messages to return (newest)

        Returns:
            List of message dictionaries
        """
        if limit is None:
            return list(self.conversation_history)
        return list(self.conversation_history[-limit:])

    def clear_history(self) -> None:
        """Clear conversation history"""
        self.conversation_history.clear()
        self.turn_count = 0

    def update_usage(self, cost: float = 0.0, tokens: int = 0) -> None:
        """
        Update usage statistics

        Args:
            cost: Cost to add
            tokens: Tokens to add
        """
        self.total_cost += cost
        self.total_tokens += tokens

    def reset(self) -> None:
        """Reset state to initial values"""
        self.running = True
        self.current_agent = "build"
        self.session = None
        self.conversation_history.clear()
        self.total_cost = 0.0
        self.total_tokens = 0
        self.turn_count = 0

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary"""
        return {
            "running": self.running,
            "current_agent": self.current_agent,
            "conversation_history": self.conversation_history,
            "total_cost": self.total_cost,
            "total_tokens": self.total_tokens,
            "turn_count": self.turn_count,
        }
