"""Semantic-Validator — LLM-Layer der HIGH-Findings semantisch prüft.

User-Vorgabe 2026-06-09: statt unendlich Regex-Pattern für jede
Schreibweise (Tel/Telefon/Telef./Telefonnr./Telefonnummer/Phone/Fon)
zu pflegen, nutzen wir einen LLM-Pass als 2. Layer:

  1. MC-Pattern fängt 95% der Standard-Schreibweisen.
  2. Bei MC-MISS einmaliger LLM-Call: "ist die Pflichtangabe semantisch
     doch da, nur unter abweichendem Label?"
  3. Wenn ja: HIGH-Finding wird zu LOW "Best-Practice Umbenennung".
  4. Wenn nein: HIGH-Finding bleibt.

Vorteile:
  - Pattern bleiben schlank
  - Output für Kunden ist konkret: "Bitte 'Management' in 'Geschäftsführer'
    umbenennen"
  - 1 LLM-Call pro Slot statt N → Cost-effizient
  - Self-correcting: Pattern-Lücken werden vom LLM gefangen
"""

from __future__ import annotations

import logging

from ._escalation import cascade

logger = logging.getLogger(__name__)


# Standard-Bezeichnungen pro field_id — der Soll-Wortlaut den der
# Kunde verwenden sollte (für die Umbenennungs-Empfehlung).
STANDARD_LABELS: dict[str, str] = {
    # Impressum
    "kontakt_telefon": "Telefon",
    "kontakt_email": "E-Mail",
    "handelsregister": "Handelsregister",
    "ust_id": "Umsatzsteuer-Identifikationsnummer (USt-IdNr.)",
    "vertretungsberechtigte": "Geschäftsführer (bei GmbH) / Vorstand (bei AG)",
    "vertretungsberechtigte_label_korrekt":
        "Geschäftsführer (bei GmbH) / Vorstand (bei AG)",
    "name_anbieter": "Anbieter / Anschrift",
    "aufsichtsbehoerde": "Aufsichtsbehörde",
    "verantwortlicher_redaktion": "Inhaltlich Verantwortlicher nach § 18 MStV",
    "verbraucher_streitbeilegung": "Verbraucherstreitbeilegung (VSBG)",
    "berufsangaben": "Berufsbezeichnung",
    "odr_link": "OS-Plattform der EU",
    # Cookie-Policy
    "categories_named": "Cookie-Kategorien (essentiell, funktional, analytics, marketing)",
    "purpose_described": "Verarbeitungszweck",
    "retention_duration": "Speicherdauer / Laufzeit",
    "vendor_recipients": "Empfänger / Drittanbieter",
    "opt_out_mechanism": "Opt-Out-Mechanismus",
    "banner_reopen": "Cookie-Einstellungen ändern",
    "version_date": "Stand / Letzte Aktualisierung",
    "third_country_transfer": "Drittland-Übermittlung (Schrems II)",
    "legal_basis": "Rechtsgrundlage (Art. 6 DSGVO / § 25 TDDDG)",
    "cookie_table_or_list": "Cookie-Tabelle",
    "dpo_contact": "Datenschutzbeauftragter (DSB)",
    "browser_settings_hint": "Browser-Einstellungen",
}


_SYSTEM_PROMPT = """Du bist Compliance-Pruefer. Aufgabe: ein Dokument
und eine Liste fehlender Pflichtangaben pruefen. Fuer JEDE Pflichtangabe
entscheiden: ist sie inhaltlich vorhanden, vielleicht unter einem
abweichenden Label/Schreibweise?

WICHTIG:
  - 'Vorhanden' nur wenn der Inhalt eindeutig erkennbar ist
    (z.B. eine Telefonnummer mit Vorwahl, nicht nur das Wort 'Telefon').
  - Bei unsicher: 'found': false zurueckgeben.
  - Wenn vorhanden: das tatsaechlich verwendete Label angeben
    (z.B. 'Management' statt 'Geschaeftsfuehrer', 'Fon' statt 'Telefon').

Antwort NUR als JSON:
{
  "results": [
    {"field_id": "...",
     "found": true|false,
     "label_used": "tatsächlich verwendetes Label",
     "evidence": "kurzes wörtliches Zitat",
     "confidence": 0.0-1.0}
  ]
}
"""


async def validate_present(
    text: str,
    missing_fields: list[tuple[str, str]],
) -> dict[str, dict]:
    """Prüft per LLM ob die genannten Felder semantisch doch im Text sind.

    Args:
      text:           Volltext des Dokuments.
      missing_fields: Liste (field_id, beschreibung) die das MC-Pattern
                       NICHT gefunden hat.

    Returns:
      dict[field_id, {"found", "label_used", "evidence", "confidence"}]
      Leeres Dict wenn LLM nicht erreichbar oder unsicher.
    """
    if not missing_fields or len(text) < 100:
        return {}
    lines = ["FEHLENDE PFLICHTANGABEN (zum Pruefen):"]
    for fid, label in missing_fields:
        lines.append(f"  - {fid}: {label}")
    lines.append("")
    lines.append(f"DOKUMENT-TEXT:\n{text[:4000]}")
    lines.append("")
    lines.append("Liste pro field_id ob die Pflichtangabe vorhanden "
                  "ist (auch unter abweichendem Label). Nur JSON.")
    user_prompt = "\n".join(lines)
    res, _logs = await cascade(_SYSTEM_PROMPT, user_prompt)
    if res is None:
        return {}
    parsed = res.parsed if isinstance(res.parsed, (dict, list)) else None
    if parsed is None:
        return {}
    rows = (parsed.get("results")
            if isinstance(parsed, dict) else parsed)
    if not isinstance(rows, list):
        return {}
    out: dict[str, dict] = {}
    for row in rows:
        if not isinstance(row, dict):
            continue
        fid = str(row.get("field_id") or "")
        if not fid:
            continue
        out[fid] = {
            "found": bool(row.get("found")),
            "label_used": str(row.get("label_used") or "")[:60],
            "evidence": str(row.get("evidence") or "")[:200],
            "confidence": float(row.get("confidence") or 0.5),
        }
    return out


def standard_label(field_id: str) -> str:
    """Soll-Bezeichnung für eine Pflichtangabe."""
    return STANDARD_LABELS.get(field_id, field_id)


def build_rename_action(
    field_id: str, label_used: str,
) -> str:
    """Erzeugt die Best-Practice-Umbenennungs-Empfehlung."""
    std = standard_label(field_id)
    return (
        f"Best-Practice Umbenennung: '{label_used}' → '{std}'. "
        f"Inhalt ist vorhanden, nur das Label weicht von der "
        f"Standard-Terminologie ab. Eine einheitliche Bezeichnung "
        f"erleichtert dem Nutzer das Auffinden der Pflichtangabe und "
        f"bei Behörden-Prüfungen die Anerkennung."
    )
