"""AGB-Routing-Pipeline (C-lean): nimmt das Keyword-Ergebnis des ChecklistAgent
und routet keyword-durchgefallene Items per `_routing.decision_method` an die
wiederverwendbare Prüfer-Library (Embedding / Reference / LLM). Davor das
Geschäftsmodell-Gate (Applicability). Das Re-Tiering (LOW → Empfehlung) +
Output-Zusammenbau macht der AGBAgent — hier nur die Routing-Entscheidung.

Validiert (7-Firmen-Opus-GT): 71 % FP → ~0. agent.py bleibt dünn, dies ist der
einzige Ort des C-lean-Flows.
"""
from __future__ import annotations

import logging

from compliance.services.checkers.base import (
    ControlSpec,
    DecisionMethod,
    DocContext,
    VerificationMethod,
)
from compliance.services.checkers.embedding_checker import EmbeddingChecker
from compliance.services.checkers.llm_checker import LLMChecker
from compliance.services.checkers.reference_checker import ReferenceChecker

from . import _routing

logger = logging.getLogger(__name__)

# Checker sind zustandslos (schwere Imports erst in .check()) → Modul-Singletons.
_EMB = EmbeddingChecker()
_REF = ReferenceChecker()
_LLM = LLMChecker()


def _spec(item_id: str) -> ControlSpec:
    """ControlSpec für ein Item aus der AGB-Routing-Config bauen."""
    dm = _routing.decision_method(item_id)
    if dm == _routing.REFERENCE:
        return ControlSpec(
            control_id=item_id, verification_method=VerificationMethod.REFERENCE,
            decision_method=DecisionMethod.LINK_RESOLVER,
            patterns=[_routing.REFERENCE_PATTERNS[item_id]],
        )
    if dm == _routing.LLM:
        return ControlSpec(
            control_id=item_id, verification_method=VerificationMethod.CONTENT,
            decision_method=DecisionMethod.LLM,
            paraphrases=_routing.PARAPHRASES.get(item_id, []),
            topic_regex=_routing.LLM_TOPIC.get(item_id, ""),
            question=_routing.LLM_QUESTION.get(item_id, ""),
        )
    return ControlSpec(
        control_id=item_id, verification_method=VerificationMethod.CONTENT,
        decision_method=DecisionMethod.EMBEDDING,
        paraphrases=_routing.PARAPHRASES.get(item_id, []),
        embed_threshold=_routing.EMBED_THRESHOLDS.get(item_id),
    )


async def _resolves(item_id: str, text: str, skip_llm: bool):
    """True = Klausel doch vorhanden (Keyword-Finding auflösen). False/None =
    Finding behalten (fail-safe: bei Unsicherheit/Service-Ausfall lieber melden)."""
    dm = _routing.decision_method(item_id)
    if dm == _routing.MERGED:
        return True  # in ein anderes Item aufgegangen → kein eigenes Finding
    doc = DocContext(text=text)
    spec = _spec(item_id)
    if dm == _routing.REFERENCE:
        return (await _REF.check(spec, doc)).present
    if dm == _routing.LLM:
        if skip_llm:
            return None  # interaktiv: kein LLM → Keyword-Ergebnis behalten
        return (await _LLM.check(spec, doc)).present
    return (await _EMB.check(spec, doc)).present


async def run_routed(base_findings: list, text: str, context: dict | None = None):
    """Routet die keyword-durchgefallenen Items.

    Returns (kept, resolved_ids, gated_ids):
      kept         = Findings, die nach Gate+Rescue bestehen bleiben
      resolved_ids = per Embedding/Reference/LLM doch als vorhanden erkannt
      gated_ids    = per Geschäftsmodell nicht anwendbar (N/A)
    """
    context = context or {}
    skip_llm = bool(context.get("skip_llm"))
    model = _routing.detect_business_model(text)
    kept, resolved, gated = [], [], []
    for f in base_findings:
        item_id = f.field_id
        if not _routing.is_applicable(item_id, model):
            gated.append(item_id)
            continue
        try:
            present = await _resolves(item_id, text, skip_llm)
        except Exception as e:  # noqa: BLE001 — best-effort, Finding behalten
            logger.info("agb routing %s failed: %s", item_id, str(e)[:80])
            present = None
        if present is True:
            resolved.append(item_id)
        else:
            kept.append(f)
    return kept, resolved, gated
