from __future__ import annotations

from app.modules.agent.intent_router_v2.analysis.docs_query_signals import DocsQuerySignals
from app.modules.agent.intent_router_v2.analysis.docs_sub_intent_detector import DocsSubIntentDetector


class DocsAmbiguityDetector:
    _ALLOWED = {
        "SYSTEM_FLOW_EXPLAIN",
        "COMPONENT_EXPLAIN",
        "API_METHOD_EXPLAIN",
        "ENTITY_EXPLAIN",
        "RELATED_DOCS_EXPLAIN",
        "GENERIC_QA",
    }

    def __init__(
        self,
        docs_signals: DocsQuerySignals | None = None,
        detector: DocsSubIntentDetector | None = None,
    ) -> None:
        self._docs_signals = docs_signals or DocsQuerySignals()
        self._detector = detector or DocsSubIntentDetector()
        self._natural_entity_markers = ("runtime health", "статус воркера", "состояние runtime", "состояние воркера")
        self._natural_flow_markers = ("health check runtime", "проверка состояния", "как работает health check", "как происходит проверка")

    def detect(self, query: str, *, intent: str, sub_intent: str) -> dict[str, object]:
        if intent not in {"DOCUMENTATION_EXPLAIN", "GENERAL_QA"}:
            return self._result(False, "", sub_intent, [])
        candidates = [name for name, _ in self._detector.rank_candidates(query, intent="DOCUMENTATION_EXPLAIN") if name in self._ALLOWED]
        if not candidates:
            return self._result(False, "", sub_intent, [])
        top_scores = self._detector.rank_candidates(query, intent="DOCUMENTATION_EXPLAIN")
        score_map = {name: score for name, score in top_scores}
        selected_score = int(score_map.get(sub_intent, 0))
        second_score = int(next((score for name, score in top_scores if name != sub_intent), 0))
        has_strong_anchor = bool(self._docs_signals.query_anchor_candidates(query)) or self._docs_signals.has_component_like_token(query)
        if sub_intent == "GENERIC_QA" and has_strong_anchor:
            return self._result(True, "general_vs_anchor_conflict", sub_intent, candidates[:4])
        if sub_intent != "GENERIC_QA" and self._looks_overview_like(query) and not has_strong_anchor:
            return self._result(True, "overview_vs_explain_conflict", sub_intent, candidates[:4])
        if not has_strong_anchor and self._looks_natural_boundary(query):
            return self._result(True, "natural_language_boundary", sub_intent, candidates[:4])
        if selected_score and second_score and selected_score - second_score <= 1 and second_score >= 2:
            return self._result(True, "small_score_gap", sub_intent, candidates[:4])
        if not has_strong_anchor and selected_score <= 3 and second_score >= 1:
            return self._result(True, "weak_deterministic_signal", sub_intent, candidates[:4])
        return self._result(False, "", sub_intent, candidates[:4])

    def _looks_overview_like(self, query: str) -> bool:
        text = " ".join((query or "").lower().split())
        return any(marker in text for marker in ("что есть в документации", "какая структура документации", "что описано", "обзор документации", "с чего начать"))

    def _looks_natural_boundary(self, query: str) -> bool:
        text = " ".join((query or "").lower().split())
        return any(marker in text for marker in (*self._natural_entity_markers, *self._natural_flow_markers))

    def _result(self, is_ambiguous: bool, reason: str, selected: str, candidates: list[str]) -> dict[str, object]:
        return {
            "is_ambiguous": is_ambiguous,
            "ambiguity_reason": reason,
            "deterministic_candidates": list(candidates),
            "deterministic_primary_candidate": selected,
        }
