"""MessageSelector — resolves target expressions to a single SessionMessage."""

import re

from session_store.errors import MessageNotFoundError
from session_store.models import SessionExport, SessionMessage

_HEAD_TIL_RE = re.compile(r"^HEAD~(\d+)$")


class MessageSelector:
    """Resolves target expressions to a single SessionMessage."""

    def resolve(self, target: str, session: SessionExport) -> SessionMessage:
        """Resolve a target expression to a single message.

        Supported target expressions:
            latest        — the most recent assistant message
            HEAD          — same as latest
            HEAD~N        — Nth message before the latest (N >= 1)
            <number>      — message at 1-based index in the session
            first         — the first assistant message
            search:<text> — first assistant message containing <text>

        Raises:
            MessageNotFoundError: If the target cannot be resolved.
            ValueError: If the target expression is malformed.
        """
        candidates = self.filter_assistant(session.messages)

        if target in ("latest", "HEAD"):
            if not candidates:
                raise MessageNotFoundError(f"No assistant messages in session {session.session_id}")
            return candidates[-1]

        head_match = _HEAD_TIL_RE.match(target)
        if head_match:
            n = int(head_match.group(1))
            idx = len(candidates) - 1 - n
            if idx < 0 or idx >= len(candidates):
                raise MessageNotFoundError(
                    f"HEAD~{n} is out of range (have {len(candidates)} assistant messages)"
                )
            return candidates[idx]

        if target.isdigit():
            n = int(target)
            if n < 1 or n > len(candidates):
                raise MessageNotFoundError(
                    f"Message number {n} is out of range "
                    f"(have {len(candidates)} assistant messages)"
                )
            return candidates[n - 1]

        if target == "first":
            if not candidates:
                raise MessageNotFoundError(f"No assistant messages in session {session.session_id}")
            return candidates[0]

        if target.startswith("search:"):
            query = target[len("search:") :]
            query_lower = query.lower()
            for msg in candidates:
                if query_lower in msg.content.lower():
                    return msg
            raise MessageNotFoundError(f"No assistant message containing '{query}'")

        raise ValueError(f"Unknown target expression: {target}")

    def filter_assistant(self, messages: list[SessionMessage]) -> list[SessionMessage]:
        """Filter to assistant messages, deduplicated by content, >50 chars.

        - Keeps only messages where role == "assistant".
        - Removes duplicates by exact content match.
        - Excludes messages with len(content) <= 50.
        - Preserves chronological order.
        """
        seen: set[str] = set()
        result: list[SessionMessage] = []
        for msg in messages:
            if msg.role != "assistant":
                continue
            if len(msg.content) <= 50:
                continue
            if msg.content in seen:
                continue
            seen.add(msg.content)
            result.append(msg)
        return result
