from __future__ import annotations

from app.modules.rag.intent_router_v2.models import (
    CodeRetrievalFilters,
    ConversationState,
    DocsRetrievalFilters,
    HybridRetrievalFilters,
    QueryAnchor,
    RepoContext,
)
from app.modules.rag.intent_router_v2.analysis.test_signals import has_test_focus, is_negative_test_request, is_test_related_token


class RetrievalFilterBuilder:
    def build(
        self,
        domains: list[str],
        anchors: list[QueryAnchor],
        repo_context: RepoContext,
        *,
        raw_query: str,
        conversation_state: ConversationState | None,
        conversation_mode: str,
        sub_intent: str = "EXPLAIN",
    ) -> CodeRetrievalFilters | DocsRetrievalFilters | HybridRetrievalFilters:
        path_scope = self._path_scope(
            anchors,
            conversation_state=conversation_state,
            conversation_mode=conversation_mode,
            raw_query=raw_query,
            sub_intent=sub_intent,
        )
        if domains == ["DOCS"]:
            return DocsRetrievalFilters(
                path_scope=path_scope,
                doc_kinds=self._doc_kinds(anchors, raw_query),
                doc_language=[],
            )
        if domains == ["CODE"]:
            return CodeRetrievalFilters(
                test_policy=self._test_policy(raw_query, anchors, sub_intent=sub_intent),
                path_scope=path_scope,
                language=list(repo_context.languages),
            )
        return HybridRetrievalFilters(
            test_policy=self._test_policy(raw_query, anchors, sub_intent=sub_intent),
            path_scope=path_scope,
            language=list(repo_context.languages),
            doc_kinds=self._doc_kinds(anchors, raw_query),
            doc_language=[],
        )

    def _test_policy(self, raw_query: str, anchors: list[QueryAnchor], *, sub_intent: str) -> str:
        if sub_intent == "FIND_TESTS":
            return "INCLUDE"
        if is_negative_test_request(raw_query):
            return "EXCLUDE"
        if has_test_focus(raw_query):
            return "INCLUDE"
        has_test_keyterm = any(anchor.type == "KEY_TERM" and is_test_related_token(anchor.value) for anchor in anchors)
        return "INCLUDE" if has_test_keyterm else "EXCLUDE"

    def _path_scope(
        self,
        anchors: list[QueryAnchor],
        *,
        conversation_state: ConversationState | None,
        conversation_mode: str,
        raw_query: str,
        sub_intent: str,
    ) -> list[str]:
        values: list[str] = []
        has_user_file_anchor = False
        file_values: list[str] = []
        for anchor in anchors:
            if anchor.type != "FILE_PATH":
                continue
            if anchor.source == "user_text":
                has_user_file_anchor = True
            if anchor.value not in values:
                values.append(anchor.value)
            if self._looks_like_file_path(anchor.value) and anchor.value not in file_values:
                file_values.append(anchor.value)
            parent = anchor.value.rsplit("/", 1)[0] if "/" in anchor.value and self._looks_like_file_path(anchor.value) else ""
            if parent and parent not in values:
                values.append(parent)
        if sub_intent in {"OPEN_FILE", "EXPLAIN_LOCAL"} and file_values and not self._is_explicit_directory_scope(raw_query):
            return file_values[:6]
        if has_user_file_anchor or conversation_mode != "CONTINUE":
            return values[:6]
        if values:
            return values[:6]
        inherited = list((conversation_state.active_path_scope if conversation_state else []) or [])
        return inherited[:6]

    def _doc_kinds(self, anchors: list[QueryAnchor], raw_query: str) -> list[str]:
        text = (raw_query or "").lower()
        kinds: list[str] = []
        has_readme = "readme" in text or any(
            anchor.type in {"DOC_REF", "FILE_PATH"} and anchor.value.lower().endswith("readme.md")
            for anchor in anchors
        )
        if has_readme:
            kinds.append("README")
        return kinds

    def _looks_like_file_path(self, value: str) -> bool:
        filename = value.rsplit("/", 1)[-1]
        return "." in filename

    def _is_explicit_directory_scope(self, raw_query: str) -> bool:
        text = (raw_query or "").lower()
        return any(marker in text for marker in ("в папке", "в директории", "в каталоге"))
