"""SessionStore — unified facade API for clients."""

from session_store.detector import AutoDetector
from session_store.errors import NoActiveSessionError, SessionNotFoundError
from session_store.models import SessionExport, SessionInfo, SessionMessage
from session_store.registry import SourceRegistry, default_registry
from session_store.selector import MessageSelector


class SessionStore:
    """Unified API for session and message access across AI agent tools.

    Composes per-tool adapters via a SourceRegistry. Clients can:
    - List sessions from all tools or a specific tool
    - Load a session's messages by session ID
    - Detect the current tool and session
    - Select a specific message by target expression
    """

    def __init__(self, registry: SourceRegistry | None = None) -> None:
        """Initialize with a registry, or use default_registry() if None."""
        self._registry = registry or default_registry()
        self._detector = AutoDetector(self._registry)
        self._selector = MessageSelector()

    # --- Session access ---

    def list_sessions(
        self,
        tool: str | None = None,
        limit: int = 20,
    ) -> list[SessionInfo]:
        """List sessions, optionally filtered to a specific tool.

        Args:
            tool: If None, list sessions from ALL registered tools,
                  merged and sorted by last_activity (most recent first).
                  If specified (e.g. "devin"), list sessions from that
                  tool only.
            limit: Maximum number of sessions to return per tool.
                   When tool is None, the limit applies per-tool, then
                   results are merged and sorted.

        Returns:
            List of SessionInfo, most recent first.
        """
        if tool is not None:
            source = self._registry.get(tool)
            return source.list_sessions(limit=limit)

        all_sessions: list[SessionInfo] = []
        for source in self._registry.all_sources():
            all_sessions.extend(source.list_sessions(limit=limit))

        all_sessions.sort(key=lambda s: s.last_activity, reverse=True)
        return all_sessions

    def get_session(self, session_id: str, tool: str | None = None) -> SessionExport:
        """Load a full session with all messages.

        Args:
            session_id: The session identifier.
            tool: If specified, load from that tool only.
                  If None, try each registered source until one finds
                  the session.

        Raises:
            SessionNotFoundError: If no source has the session.
        """
        if tool is not None:
            source = self._registry.get(tool)
            return source.load_session(session_id)

        for source in self._registry.all_sources():
            try:
                return source.load_session(session_id)
            except SessionNotFoundError:
                continue

        raise SessionNotFoundError(f"Session '{session_id}' not found in any registered source")

    # --- Message access ---

    def get_messages(self, session_id: str, tool: str | None = None) -> list[SessionMessage]:
        """Get all messages in a session.

        Convenience method — equivalent to get_session().messages.

        Args:
            session_id: The session identifier.
            tool: If specified, load from that tool only.

        Raises:
            SessionNotFoundError: If no source has the session.
        """
        return self.get_session(session_id, tool=tool).messages

    def select_message(
        self,
        target: str,
        session_id: str | None = None,
        tool: str | None = None,
    ) -> SessionMessage:
        """Select a single message by target expression.

        Args:
            target: Target expression (latest, HEAD~N, <number>, first, search:<text>).
            session_id: Session to search. If None, auto-detects the current session.
            tool: If specified, restricts auto-detection to that tool.

        Raises:
            MessageNotFoundError: If the target cannot be resolved.
            NoActiveSessionError: If session_id is None and detection fails.
        """
        if session_id is None:
            detected_tool = tool or self.detect_tool()
            session_id = self.detect_session(tool=detected_tool)
            if session_id is None:
                raise NoActiveSessionError(
                    f"No active session detected for tool '{detected_tool}'. Specify --session-id."
                )
            tool = detected_tool

        session = self.get_session(session_id, tool=tool)
        return self._selector.resolve(target, session)

    # --- Auto-detection ---

    def detect_tool(self) -> str:
        """Detect which AI agent tool was most recently active.

        Raises:
            NoActiveSessionError: If no source has any sessions.
        """
        return self._detector.detect_tool()

    def detect_session(self, tool: str | None = None, cwd: str | None = None) -> str | None:
        """Detect the current session ID.

        Args:
            tool: If specified, detect for that tool only.
                  If None, auto-detects the tool first.
            cwd: If provided, prefers a session whose working_directory matches.

        Returns:
            The session ID, or None if no session could be detected.
        """
        if tool is None:
            tool = self.detect_tool()
        return self._detector.detect_session(tool, cwd=cwd)
