"""Политика принятия решения: вызывать LLM или вернуть короткий ответ по evidence gate."""

from __future__ import annotations

from dataclasses import dataclass

from app.modules.agent.runtime.steps.gates.pre.evidence_gate import EvidenceGateDecision
from app.modules.agent.intent_router_v2.models import IntentRouterResult
from app.modules.agent.runtime.steps.answer_policy.short_answer_formatter import RuntimeShortAnswerFormatter


@dataclass(slots=True, frozen=True)
class RuntimePolicyDecision:
    answer_mode: str
    answer: str = ""
    should_call_llm: bool = True
    branch: str = "normal_answer"
    reason: str = "evidence_sufficient"


class RuntimeAnswerPolicy:
    def __init__(self, formatter: RuntimeShortAnswerFormatter | None = None) -> None:
        self._formatter = formatter or RuntimeShortAnswerFormatter()

    def decide(
        self,
        *,
        router_result: IntentRouterResult,
        gate_decision: EvidenceGateDecision,
    ) -> RuntimePolicyDecision:
        sub_intent = router_result.query_plan.sub_intent.upper()
        symbol_resolution = router_result.symbol_resolution
        if sub_intent == "OPEN_FILE" and "path_scope_empty" in gate_decision.failure_reasons:
            path_scope = list(getattr(router_result.retrieval_spec.filters, "path_scope", []) or [])
            target = path_scope[0] if path_scope else "запрошенный файл"
            return RuntimePolicyDecision(
                answer_mode="not_found",
                answer=self._formatter.open_file_not_found(target),
                should_call_llm=False,
                branch="open_file_not_found",
                reason="path_scope_empty",
            )
        if sub_intent == "EXPLAIN" and symbol_resolution.status == "not_found":
            return RuntimePolicyDecision(
                answer_mode="not_found",
                answer=self._formatter.entity_not_found(self._target_label(router_result), symbol_resolution.alternatives),
                should_call_llm=False,
                branch="explain_not_found",
                reason="symbol_resolution_not_found",
            )
        if sub_intent == "EXPLAIN" and symbol_resolution.status == "ambiguous":
            return RuntimePolicyDecision(
                answer_mode="ambiguous",
                answer=self._formatter.entity_ambiguous(self._target_label(router_result), symbol_resolution.alternatives),
                should_call_llm=False,
                branch="explain_ambiguous_symbol",
                reason="symbol_resolution_ambiguous",
            )
        if not gate_decision.passed:
            answer_mode = "insufficient" if "insufficient_evidence" in gate_decision.failure_reasons else "degraded"
            reason = gate_decision.failure_reasons[0] if gate_decision.failure_reasons else "evidence_gate_failed"
            return RuntimePolicyDecision(
                answer_mode=answer_mode,
                answer=self._formatter.insufficient(gate_decision.degraded_message),
                should_call_llm=False,
                branch="evidence_gate_short_circuit",
                reason=reason,
            )
        return RuntimePolicyDecision(answer_mode="normal", branch="normal_answer", reason="evidence_sufficient")

    def _target_label(self, router_result: IntentRouterResult) -> str:
        candidates = [item.strip() for item in list(router_result.query_plan.symbol_candidates or []) if item and item.strip()]
        return candidates[0] if candidates else "запрошенная сущность"
