from app.modules.agent.engine.router.context_store import RouterContextStore
from app.modules.agent.engine.router.intent_classifier import IntentClassifier
from app.modules.agent.engine.router.intent_switch_detector import IntentSwitchDetector
from app.modules.agent.engine.router.registry import IntentRegistry
from app.modules.agent.engine.router.schemas import RouteDecision, RouteResolution


class RouterService:
    def __init__(
        self,
        registry: IntentRegistry,
        classifier: IntentClassifier,
        context_store: RouterContextStore,
        switch_detector: IntentSwitchDetector | None = None,
        min_confidence: float = 0.7,
    ) -> None:
        self._registry = registry
        self._classifier = classifier
        self._ctx = context_store
        self._switch_detector = switch_detector or IntentSwitchDetector()
        self._min_confidence = min_confidence

    def resolve(self, user_message: str, conversation_key: str, mode: str = "auto") -> RouteResolution:
        context = self._ctx.get(conversation_key)
        forced = self._classifier.from_mode(mode)
        if forced:
            return self._resolution(forced)

        if not context.dialog_started or context.active_intent is None:
            decision = self._classifier.classify_new_intent(user_message, context)
            if not self._is_acceptable(decision):
                return self._fallback("low_confidence")
            return self._resolution(
                decision.model_copy(
                    update={
                        "decision_type": "start",
                        "explicit_switch": False,
                    }
                )
            )

        if self._switch_detector.should_switch(user_message, context):
            decision = self._classifier.classify_new_intent(user_message, context)
            if self._is_acceptable(decision):
                return self._resolution(
                    decision.model_copy(
                        update={
                            "decision_type": "switch",
                            "explicit_switch": True,
                        }
                    )
                )
            return self._continue_current(context, "explicit_switch_unresolved_keep_current")

        return self._continue_current(context, "continue_current_intent")

    def persist_context(
        self,
        conversation_key: str,
        *,
        domain_id: str,
        process_id: str,
        user_message: str,
        assistant_message: str,
        decision_type: str = "start",
    ) -> None:
        self._ctx.update(
            conversation_key,
            domain_id=domain_id,
            process_id=process_id,
            user_message=user_message,
            assistant_message=assistant_message,
            decision_type=decision_type,
        )

    def graph_factory(self, domain_id: str, process_id: str):
        return self._registry.get_factory(domain_id, process_id)

    def _fallback(self, reason: str) -> RouteResolution:
        return RouteResolution(
            domain_id="default",
            process_id="general",
            confidence=0.0,
            reason=reason,
            fallback_used=True,
            decision_type="start",
            explicit_switch=False,
        )

    def _continue_current(self, context, reason: str) -> RouteResolution:
        active = context.active_intent or context.last_routing or {"domain_id": "default", "process_id": "general"}
        return RouteResolution(
            domain_id=str(active["domain_id"]),
            process_id=str(active["process_id"]),
            confidence=1.0,
            reason=reason,
            fallback_used=False,
            decision_type="continue",
            explicit_switch=False,
        )

    def _is_acceptable(self, decision: RouteDecision) -> bool:
        return decision.confidence >= self._min_confidence and self._registry.is_valid(decision.domain_id, decision.process_id)

    def _resolution(self, decision: RouteDecision) -> RouteResolution:
        return RouteResolution(
            domain_id=decision.domain_id,
            process_id=decision.process_id,
            confidence=decision.confidence,
            reason=decision.reason,
            fallback_used=False,
            decision_type=decision.decision_type,
            explicit_switch=decision.explicit_switch,
        )
