"""Session management for Oclawma.

This module provides the interactive REPL-style session for Oclawma,
including conversation history management, tool calling, and graceful exit handling.
"""

from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Optional


@dataclass
class SessionMessage:
    """A message in the conversation history."""

    role: str  # "system", "user", "assistant", "tool"
    content: str
    timestamp: datetime = field(default_factory=datetime.now)
    metadata: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary format for LLM APIs."""
        return {
            "role": self.role,
            "content": self.content,
            **({"name": self.metadata["name"]} if "name" in self.metadata else {}),
        }


@dataclass
class SessionStats:
    """Statistics for a session."""

    start_time: datetime
    end_time: Optional[datetime] = None
    message_count: int = 0
    user_messages: int = 0
    assistant_messages: int = 0
    tool_calls: int = 0
    tokens_used: int = 0
    tool_results: list[str] = field(default_factory=list)


class ConversationHistory:
    """Manages conversation history for a session."""

    def __init__(self, max_messages: int = 100) -> None:
        """Initialize conversation history.

        Args:
            max_messages: Maximum number of messages to keep
        """
        self._messages: list[SessionMessage] = []
        self._max_messages = max_messages

    def add_message(
        self,
        role: str,
        content: str,
        metadata: Optional[dict[str, Any]] = None,
    ) -> SessionMessage:
        """Add a message to the history.

        Args:
            role: Message role ("system", "user", "assistant", "tool")
            content: Message content
            metadata: Optional metadata

        Returns:
            The created message
        """
        message = SessionMessage(
            role=role,
            content=content,
            metadata=metadata or {},
        )
        self._messages.append(message)

        # Trim if exceeding max
        if len(self._messages) > self._max_messages:
            # Keep system message if present, remove oldest non-system
            if self._messages and self._messages[0].role == "system":
                self._messages.pop(1)
            else:
                self._messages.pop(0)

        return message

    def get_messages(self, include_system: bool = True) -> list[SessionMessage]:
        """Get all messages.

        Args:
            include_system: Whether to include system messages

        Returns:
            List of messages
        """
        if include_system:
            return list(self._messages)
        return [m for m in self._messages if m.role != "system"]

    def get_recent(self, n: int) -> list[SessionMessage]:
        """Get the n most recent messages.

        Args:
            n: Number of messages to get

        Returns:
            List of recent messages
        """
        return self._messages[-n:] if n < len(self._messages) else list(self._messages)

    def to_llm_messages(self) -> list[dict[str, str]]:
        """Convert messages to LLM API format.

        Returns:
            List of message dictionaries
        """
        return [
            {
                "role": msg.role,
                "content": msg.content,
            }
            for msg in self._messages
        ]

    def clear(self) -> None:
        """Clear all messages."""
        self._messages.clear()

    def set_system_message(self, content: str) -> None:
        """Set or update the system message.

        Args:
            content: System message content
        """
        # Remove existing system message
        self._messages = [m for m in self._messages if m.role != "system"]
        # Add new system message at the beginning
        self._messages.insert(
            0,
            SessionMessage(role="system", content=content),
        )

    def __len__(self) -> int:
        """Return the number of messages."""
        return len(self._messages)

    def estimate_tokens(self) -> int:
        """Estimate token count for all messages.

        Uses a rough approximation of 4 characters per token.

        Returns:
            Estimated token count
        """
        total_chars = sum(len(m.content) for m in self._messages)
        # Rough approximation: ~4 chars per token + overhead per message
        overhead = len(self._messages) * 4
        return (total_chars // 4) + overhead


# Import runner classes for convenience
# Import rolling history summarizer
from oclawma.session.history_summarizer import (  # noqa: E402
    FactStore,
    RollingHistorySummarizer,
    SummaryConfig,
    SummaryResult,
)
from oclawma.session.runner import InteractiveSession, SessionExitError  # noqa: E402

__all__ = [
    "SessionMessage",
    "SessionStats",
    "ConversationHistory",
    "InteractiveSession",
    "SessionExitError",
    "RollingHistorySummarizer",
    "SummaryConfig",
    "SummaryResult",
    "FactStore",
]
