"""CONTENT/CONTRACTUAL-Pruefer / decision_method=LLM.

present/absent ueber die LLM-Kaskade (`call_with_cascade`; prod: OVH-120b zuerst).
Retrieval = GANZE Paragraph-Abschnitte zum Topic (nicht Top-k-Chunks — das war in
der AGB-Validierung der Schluessel). KEIN DEFECT — Korrektheits-/Defekt-Pruefung
ist ein separater Modus. present=None bei Fehler (fail-safe: Aufrufer behaelt
Keyword-Ergebnis). (Validiert an AGB delivery/warranty.)
"""
from __future__ import annotations

import json
import logging
import re

from .base import CheckResult, ControlSpec, DocContext, VerificationMethod

logger = logging.getLogger(__name__)

_SECTION = re.compile(r"(?m)(?=^\s*(?:§\s*)?\d+[\.\)]\s)")
_SYS = (
    "Du bist deutscher Compliance-Rechtsexperte. Entscheide, ob die genannte "
    "Pflicht in den vorgelegten Abschnitten vorhanden ist. NUR die Abschnitte "
    'zaehlen. Antworte NUR JSON: {"verdict":"ERFUELLT|FEHLT","zitat":"woertlich '
    'oder leer","begruendung":"1 Satz"}.'
)


def _sections(text: str) -> list[str]:
    return [s.strip() for s in _SECTION.split(text) if s.strip()]


def _parse(txt: str) -> dict:
    out = (txt or "").strip()
    if out.startswith("```"):
        out = out.split("```", 2)[1]
        out = out[4:] if out.startswith("json") else out
    a, b = out.find("{"), out.rfind("}")
    return json.loads(out[a:b + 1] if 0 <= a < b else out)


class LLMChecker:
    verification_method = VerificationMethod.CONTENT

    async def check(self, ctrl: ControlSpec, doc: DocContext) -> CheckResult:
        text = doc.text or ""
        if len(text) < 50:
            return CheckResult(present=None, source="llm")
        # decision_method=LLM mit judge='haiku': Sufficiency-Pfad (validiert
        # P0.89/R0.91). Der Qwen-first-Cascade ist als Sufficiency-Judge
        # widerlegt -> hier Haiku direkt, kriteriengeführte Subsumtion.
        if (ctrl.extra or {}).get("judge") == "haiku":
            return await self._haiku(ctrl, text)
        secs = _sections(text)
        if ctrl.topic_regex:
            rel = [s for s in secs if re.search(ctrl.topic_regex, s, re.I)][:6] or secs[:6]
        else:
            rel = secs[:6]
        question = ctrl.question or f"Ist die Pflicht '{ctrl.label}' im Text vorhanden?"
        try:
            from compliance.services.llm_cascade import call_with_cascade
            r = await call_with_cascade(
                _SYS,
                json.dumps({"frage": question, "abschnitte": rel}, ensure_ascii=False),
                min_confidence=0.6, max_tokens=500,
            )
            obj = _parse(r.get("text"))
            verdict = obj.get("verdict")
            zitat = (obj.get("zitat") or "")[:120]
            if verdict not in ("ERFUELLT", "FEHLT"):
                return CheckResult(present=None, evidence=zitat, source=r.get("source", "?"))
            return CheckResult(
                present=verdict == "ERFUELLT", evidence=zitat,
                confidence=float(r.get("confidence") or 0.0),
                source=r.get("source", "llm"),
            )
        except Exception as e:
            logger.info("llm checker fail %s: %s", ctrl.control_id, str(e)[:80])
            return CheckResult(present=None, source="error")

    async def _haiku(self, ctrl: ControlSpec, text: str) -> CheckResult:
        """Sufficiency via Haiku direkt (validierter Judge). Kriteriengeführt:
        die Rechts-Elemente stehen in ctrl.paraphrases; wiederverwendet den
        validierten deep_check-Sufficiency-Prompt."""
        try:
            from compliance.services.llm_cascade import _call_anthropic
            from compliance.services.specialist_agents.dse.deep_check import (
                _JUDGE_SYS, _build_user, _parse as _parse_judge,
            )
            crit = ctrl.paraphrases or [ctrl.label or ctrl.control_id]
            user = _build_user(text, ctrl.label or ctrl.control_id, crit)
            obj = None
            for _ in range(2):
                obj = _parse_judge(await _call_anthropic(_JUDGE_SYS, user, max_tokens=400))
                if obj:
                    break
            if not obj:
                return CheckResult(present=None, source="haiku")
            return CheckResult(
                present=bool(obj.get("erfuellt")),
                evidence=(obj.get("begruendung") or "")[:120],
                confidence=float(obj.get("confidence") or 0.0),
                source="haiku",
            )
        except Exception as e:
            logger.info("llm haiku checker fail %s: %s", ctrl.control_id, str(e)[:80])
            return CheckResult(present=None, source="error")
