from __future__ import annotations

from app.modules.rag.intent_router_v2.intent.classifier import IntentClassifierV2
from app.modules.rag.intent_router_v2.intent.conversation_policy import ConversationPolicy
from app.modules.rag.intent_router_v2.retrieval.evidence_policy_factory import EvidencePolicyFactory
from app.modules.rag.intent_router_v2.intent.graph_id_resolver import GraphIdResolver
from app.modules.rag.intent_router_v2.logger import IntentRouterLogger
from app.modules.rag.intent_router_v2.models import ConversationState, IntentRouterResult, RepoContext, SymbolResolution
from app.modules.rag.intent_router_v2.analysis.query_plan_builder import QueryPlanBuilder
from app.modules.rag.intent_router_v2.retrieval.retrieval_constraints_factory import RetrievalConstraintsFactory
from app.modules.rag.intent_router_v2.retrieval.retrieval_spec_factory import RetrievalSpecFactory


class IntentRouterV2:
    def __init__(
        self,
        classifier: IntentClassifierV2 | None = None,
        conversation_policy: ConversationPolicy | None = None,
        query_plan_builder: QueryPlanBuilder | None = None,
        retrieval_factory: RetrievalSpecFactory | None = None,
        constraints_factory: RetrievalConstraintsFactory | None = None,
        evidence_factory: EvidencePolicyFactory | None = None,
        graph_resolver: GraphIdResolver | None = None,
        logger: IntentRouterLogger | None = None,
    ) -> None:
        self._classifier = classifier or IntentClassifierV2()
        self._conversation_policy = conversation_policy or ConversationPolicy()
        self._query_plan_builder = query_plan_builder or QueryPlanBuilder()
        self._retrieval_factory = retrieval_factory or RetrievalSpecFactory()
        self._constraints_factory = constraints_factory or RetrievalConstraintsFactory()
        self._evidence_factory = evidence_factory or EvidencePolicyFactory()
        self._graph_resolver = graph_resolver or GraphIdResolver()
        self._logger = logger or IntentRouterLogger()

    def route(
        self,
        user_query: str,
        conversation_state: ConversationState | None = None,
        repo_context: RepoContext | None = None,
    ) -> IntentRouterResult:
        state = conversation_state or ConversationState()
        context = repo_context or RepoContext()
        self._logger.log_request(user_query, state, context)
        decision = self._classifier.classify(user_query, state)
        intent, conversation_mode = self._conversation_policy.resolve(decision, user_query, state)
        retrieval_profile = self._resolve_retrieval_profile(intent)
        query_plan = self._query_plan_builder.build(
            user_query,
            state,
            continue_mode=conversation_mode in {"CONTINUE", "FOLLOWUP_LIKELY"},
            conversation_mode=conversation_mode,
            intent=intent,
        )
        retrieval_spec = self._retrieval_factory.build(
            intent,
            query_plan.anchors,
            context,
            raw_query=query_plan.raw,
            conversation_state=state,
            conversation_mode=conversation_mode,
            sub_intent=query_plan.sub_intent,
        )
        path_scope = list(getattr(retrieval_spec.filters, "path_scope", []) or [])
        result = IntentRouterResult(
            intent=intent,
            retrieval_profile=retrieval_profile,
            graph_id=self._graph_resolver.resolve(intent),
            conversation_mode=conversation_mode,
            query_plan=query_plan,
            retrieval_spec=retrieval_spec,
            retrieval_constraints=self._constraints_factory.build(
                retrieval_profile=retrieval_profile,
                sub_intent=query_plan.sub_intent,
                raw_query=query_plan.raw,
                anchors=query_plan.anchors,
                path_scope=path_scope,
            ),
            symbol_resolution=self._initial_symbol_resolution(
                retrieval_profile,
                query_plan.sub_intent,
                query_plan.symbol_candidates,
            ),
            evidence_policy=self._evidence_factory.build(
                intent,
                sub_intent=query_plan.sub_intent,
                negations=query_plan.negations,
                has_user_anchor=any(anchor.source == "user_text" for anchor in query_plan.anchors),
            ),
        )
        self._logger.log_result(result)
        return result

    def _initial_symbol_resolution(
        self,
        retrieval_profile: str,
        sub_intent: str,
        symbol_candidates: list[str],
    ) -> SymbolResolution:
        if retrieval_profile == "docs":
            return SymbolResolution(status="not_requested")
        if sub_intent == "OPEN_FILE":
            return SymbolResolution(status="not_requested")
        if not symbol_candidates:
            return SymbolResolution(status="not_requested")
        return SymbolResolution(
            status="pending",
            resolved_symbol=None,
            alternatives=list(symbol_candidates),
            confidence=0.0,
        )

    def _resolve_retrieval_profile(self, intent: str) -> str:
        if intent == "DOCS_QA":
            return "docs"
        return "code"
