from __future__ import annotations

from app.core.agent.utils.process_v2.anchor_signals import anchor_signal_types
from app.core.agent.utils.process_v2.models import V2AnchorType, V2Intent, V2RouteResult, V2Subintent
from app.core.rag.contracts.enums import RagLayer
from app.core.rag.retrieval.session_retriever import RetrievalPlan


class DocExplainSummaryRetrievalPolicy:
    _SUMMARY_LAYERS = {
        "docs_api_method_explain": [
            RagLayer.DOCS_DOCUMENT_CATALOG,
            RagLayer.DOCS_FACT_INDEX,
            RagLayer.DOCS_DOC_CHUNKS,
        ],
        "docs_summary_api_endpoint": [
            RagLayer.DOCS_DOCUMENT_CATALOG,
            RagLayer.DOCS_FACT_INDEX,
            RagLayer.DOCS_DOC_CHUNKS,
        ],
        "docs_summary_logic_flow": [
            RagLayer.DOCS_WORKFLOW_INDEX,
            RagLayer.DOCS_DOCUMENT_CATALOG,
            RagLayer.DOCS_DOC_CHUNKS,
        ],
        "docs_summary_domain_entity": [
            RagLayer.DOCS_ENTITY_CATALOG,
            RagLayer.DOCS_DOCUMENT_CATALOG,
            RagLayer.DOCS_DOC_CHUNKS,
        ],
        "docs_summary_architecture": [
            RagLayer.DOCS_DOCUMENT_CATALOG,
            RagLayer.DOCS_RELATION_GRAPH,
            RagLayer.DOCS_DOC_CHUNKS,
        ],
        "docs_summary_generic": [
            RagLayer.DOCS_DOCUMENT_CATALOG,
            RagLayer.DOCS_DOC_CHUNKS,
        ],
    }
    _API_DOC_PREFIXES = ["docs/api/", "docs/endpoints/", "docs/methods/", "api/", "endpoints/", "methods/"]

    def supports(self, route: V2RouteResult) -> bool:
        return route.intent == V2Intent.DOC_EXPLAIN and route.subintent == V2Subintent.SUMMARY

    def resolve(self, route: V2RouteResult) -> RetrievalPlan:
        profile = self._profile(route)
        return RetrievalPlan(
            profile=profile,
            layers=list(self._SUMMARY_LAYERS[profile]),
            limit=10 if profile == "docs_api_method_explain" else 8,
            filters=self._filters(route),
        )

    def _filters(self, route: V2RouteResult) -> dict[str, object]:
        if self._is_api_method_explain(route):
            return self._api_method_filters(route)
        filters = self._base_filters(route)
        filters["prefer_path_prefixes"] = self._summary_prefixes(route)
        filters["prefer_like_patterns"] = self._prefer_like_patterns(route)
        if V2AnchorType.API_ENDPOINT in anchor_signal_types(route):
            filters["path_prefixes"] = ["docs/api/", "docs/"]
        return filters

    def _base_filters(self, route: V2RouteResult) -> dict[str, object]:
        filters: dict[str, object] = {"target_doc_hints": list(route.anchors.target_doc_hints)}
        if route.anchors.process_domain:
            filters["metadata.domain"] = route.anchors.process_domain
        if route.anchors.process_subdomain:
            filters["metadata.subdomain"] = route.anchors.process_subdomain
        return filters

    def _api_method_filters(self, route: V2RouteResult) -> dict[str, object]:
        filters = self._base_filters(route)
        filters["path_prefixes"] = list(self._API_DOC_PREFIXES)
        filters["prefer_path_prefixes"] = list(self._API_DOC_PREFIXES)
        filters["prefer_like_patterns"] = self._api_method_patterns(route)
        return filters

    def _profile(self, route: V2RouteResult) -> str:
        if self._is_api_method_explain(route):
            return "docs_api_method_explain"
        meaningful = anchor_signal_types(route) - {V2AnchorType.FIND_FILES}
        if len(meaningful) != 1:
            return "docs_summary_generic"
        mapping = {
            V2AnchorType.API_ENDPOINT: "docs_summary_api_endpoint",
            V2AnchorType.ARCHITECTURE: "docs_summary_architecture",
            V2AnchorType.LOGIC_FLOW: "docs_summary_logic_flow",
            V2AnchorType.DOMAIN_ENTITY: "docs_summary_domain_entity",
        }
        return mapping.get(next(iter(meaningful)), "docs_summary_generic")

    def _summary_prefixes(self, route: V2RouteResult) -> list[str]:
        signals = anchor_signal_types(route)
        prefixes: list[str] = []
        if V2AnchorType.API_ENDPOINT in signals:
            prefixes.extend(["docs/api/", "docs/"])
        if V2AnchorType.ARCHITECTURE in signals:
            prefixes.extend(["docs/architecture/", "docs/"])
        if V2AnchorType.LOGIC_FLOW in signals:
            prefixes.extend(["docs/logic/", "docs/architecture/", "docs/"])
        if V2AnchorType.DOMAIN_ENTITY in signals:
            prefixes.extend(["docs/domains/", "docs/", "docs/api/"])
        return _unique_terms(prefixes or ["docs/"])

    def _prefer_like_patterns(self, route: V2RouteResult) -> list[str]:
        terms = [hint.rsplit("/", 1)[-1] for hint in route.anchors.target_doc_hints if str(hint).strip()]
        terms.extend(route.anchors.endpoint_paths)
        terms.extend(route.target_terms)
        terms.extend(route.anchors.file_names)
        terms.extend(route.anchors.entity_names)
        terms.extend(route.anchors.matched_aliases)
        if route.anchors.process_domain:
            terms.append(route.anchors.process_domain)
        if route.anchors.process_subdomain:
            terms.append(route.anchors.process_subdomain)
        return [f"%{term.lower()}%" for term in _unique_terms(terms)]

    def _api_method_patterns(self, route: V2RouteResult) -> list[str]:
        terms = [hint.rsplit("/", 1)[-1] for hint in route.anchors.target_doc_hints if str(hint).strip()]
        terms.extend(route.anchors.target_doc_hints)
        terms.extend(route.anchors.endpoint_paths)
        terms.extend(route.target_terms)
        patterns: list[str] = []
        for term in _unique_terms(terms):
            lowered = term.lower()
            stripped = lowered.strip("/")
            if stripped:
                patterns.append(f"%{stripped}%")
            if lowered:
                patterns.append(f"%{lowered}%")
        return _unique_terms(patterns)

    def _is_api_method_explain(self, route: V2RouteResult) -> bool:
        if route.subintent != V2Subintent.SUMMARY:
            return False
        if route.anchors.endpoint_paths:
            return True
        if _has_api_like_hints(route.anchors.target_doc_hints):
            return True
        return V2AnchorType.API_ENDPOINT in anchor_signal_types(route)


def _unique_terms(items: list[str]) -> list[str]:
    seen: set[str] = set()
    unique: list[str] = []
    for raw in items:
        value = str(raw or "").strip()
        if not value or value in seen:
            continue
        seen.add(value)
        unique.append(value)
    return unique


def _has_api_like_hints(hints: list[str]) -> bool:
    for hint in hints:
        value = str(hint or "").strip().lower()
        if not value:
            continue
        if value.startswith("/"):
            return True
        if value.startswith(("docs/api/", "docs/endpoints/", "docs/methods/")):
            return True
        if "endpoint" in value or "method" in value:
            return True
    return False
