"""Layer-0 Regex-Boost — meine 12 Patterns als deterministische Vor-Stufe
vor dem Keyword-Match aus doc_check_controls.

Idee (Sprint 1.12, User-Vorgabe 2026-06-09):
  - rag_document_checker.py macht Keyword-Match aus den natursprachlichen
    pass_criteria der 75 Impressum-MCs in der DB. Wenn 60% der Keywords
    matchen → PASS.
  - Bei FAIL läuft Embedding-Match (Layer 2).
  - MEIN Beitrag (Layer 0): meine 12 enger gefassten Regex-Pattern
    laufen ZUERST. Wenn ein Pattern matched → das thematisch passende
    MC wird zu PASS überschrieben (auch wenn Keyword-Match unklar war).
  - Mapping: jedem meiner field_id → Liste von Schlüsselwörtern wie sie
    in pass_criteria stehen würden. Wenn pass_criteria diese Wörter
    enthält → dieses MC gehört zu meinem field_id.

Damit gehen meine 12 Pattern nicht verloren, sondern boost'en das
bestehende System.
"""

from __future__ import annotations

import logging

from .mcs import MCS, detect_automotive, scope_matches

logger = logging.getLogger(__name__)


# Für jedes meiner field_id: welche Wörter erscheinen typisch in
# der pass_criteria der zugehörigen DB-MCs? Wenn diese Wörter im
# pass_criteria gefunden werden, ist es vermutlich derselbe MC.
# Initial-Seed der Standard-Synonyme pro field_id. User-Vorgabe
# 2026-06-09: manuelle Erweiterung als Initial-Seed ist OK; das
# LLM-basierte Auto-Learning (Sprint 1.10/1.11) ergänzt zur Laufzeit
# weitere Tail-Schreibweisen, sodass über die Zeit asymptotisch
# weniger LLM-Calls nötig sind.
BOOST_KEYWORDS: dict[str, tuple[str, ...]] = {
    "name_anbieter": (
        # Adresse / Anschrift
        "anschrift", "adresse", "postadresse", "postalisch",
        "geschäftsadresse", "geschäftssitz", "firmensitz",
        "niederlassung", "niederlassungsort", "sitz", "ort",
        "straße", "hausnummer", "plz",
        # Firmenname / Rechtsform
        "firma", "firmenname", "rechtsform", "kaufmann",
        "anbieter", "diensteanbieter", "verantwortlich",
        "anbieterkennzeichnung", "unternehmen",
    ),
    "kontakt_email": (
        "e-mail", "email", "elektronische", "kontaktmöglichkeit",
        "kontaktdaten", "mailadresse", "e-mail-adresse",
    ),
    "kontakt_telefon": (
        "telefon", "rufnummer", "telefonnummer", "phone",
        "kontaktdaten", "telekommunikation", "fax",
    ),
    "handelsregister": (
        "handelsregister", "registergericht", "hrb", "hra",
        "registernummer", "registereintrag",
        "handelsregisternummer", "handelsregisterauszug",
    ),
    "ust_id": (
        "umsatzsteuer", "ust-id", "ust-idnr",
        "umsatzsteueridentifikation",
        "umsatzsteueridentifikationsnummer", "vat",
    ),
    "vertretungsberechtigte": (
        "geschäftsführer", "geschäftsführung", "vorstand",
        "vorsitzender", "vorstandsvorsitzender",
        "vertretungsberechtigt", "vertretung", "vertreten",
        "gesellschafter", "kaufmann", "inhaber",
    ),
    "vertretungsberechtigte_label_korrekt": (
        "geschäftsführer", "vorstand", "deutsche", "bezeichnung",
        "rechtsform",
    ),
    "aufsichtsbehoerde": (
        "aufsichtsbehörde", "aufsicht", "behörde",
        "regulierungsbehörde", "ihk", "bafin", "bnetza", "kba",
    ),
    "verantwortlicher_redaktion": (
        "redaktion", "verantwortlich", "rstv", "mstv",
        "journalistisch", "publizistisch", "v.i.s.d.p",
    ),
    "verbraucher_streitbeilegung": (
        "streitbeilegung", "vsbg", "verbraucherschlichtung",
        "schlichtungsstelle", "verbraucherschlichtungsstelle",
    ),
    "berufsangaben": (
        "berufsbezeichnung", "berufsordnung", "kammer",
        "berufsrecht", "berufsverband",
    ),
    "odr_link": (
        "online-streitbeilegung", "os-plattform", "odr",
        "europäische kommission", "ec.europa.eu",
    ),
}


def compute_regex_boosts(text: str, business_scope: set[str]) -> set[str]:
    """Welche meiner field_ids hat das Pattern erkannt?

    Returns die Menge an gehit'ten field_ids für die später entschieden
    wird ob ein doc_check_control darüber automatisch passed werden kann.
    """
    if not text or len(text) < 50:
        return set()
    hits: set[str] = set()
    is_auto = detect_automotive(text)
    for mc in MCS:
        if not scope_matches(mc, business_scope, is_auto):
            continue
        if any(p.search(text) for p in mc.patterns):
            hits.add(mc.field_id)
    return hits


def boost_matches_db_mc(
    boosts: set[str],
    pass_criteria: list,
    fail_criteria: list | None = None,
) -> str | None:
    """Hat ein gebooster field_id genug Keyword-Überlapp mit den
    pass_criteria + fail_criteria einer DB-MC, um den MC zu boost'en?

    Returns: field_id (matched, mit höchstem Keyword-Match-Count), oder None.

    Schwelle: ≥2 unique Boost-Keywords im kombinierten Text.
    Beide criteria-Listen werden berücksichtigt — fail_criteria-Wörter
    wie 'Keine Adresse angegeben' helfen das MC eindeutig zuzuordnen.
    """
    if not boosts:
        return None
    crit_parts: list[str] = []
    for c in (pass_criteria or []):
        if c:
            crit_parts.append(str(c).lower())
    for c in (fail_criteria or []):
        if c:
            crit_parts.append(str(c).lower())
    if not crit_parts:
        return None
    crit_text = " ".join(crit_parts)
    best: tuple[int, str] | None = None
    for field_id in boosts:
        kws = BOOST_KEYWORDS.get(field_id) or ()
        # zähle UNIQUE hits — gleiches keyword im selben Text zählt einmal
        match_count = sum(1 for kw in kws if kw in crit_text)
        if match_count >= 2:
            if best is None or match_count > best[0]:
                best = (match_count, field_id)
    return best[1] if best else None


def criteria_on_topic(
    pass_criteria: list | None,
    fail_criteria: list | None = None,
    min_hits: int = 2,
) -> bool:
    """Deterministischer Themen-Gate: gehoert eine DB-MC ueberhaupt ins
    Impressum-Themenfeld?

    Prueft ob die kombinierten pass/fail_criteria mindestens `min_hits`
    UNTERSCHIEDLICHE Schluesselwoerter aus IRGENDEINEM der 12 Impressum-
    Felder (BOOST_KEYWORDS) enthalten. Fremd-MCs (z.B. 'Bestellbestaetigung',
    'behoerdliche Anzeige'), die faelschlich unter doc_type='impressum'
    getaggt sind, haben keinen Themen-Ueberlapp und werden so aussortiert
    — unabhaengig von DB-Sidecar/Klassifikation.

    Konservativ in beide Richtungen:
      - ein einzelner inzidenteller Treffer (z.B. 'E-Mail' in einer
        Bestellbestaetigung) reicht NICHT -> >=2 verschiedene Stichwoerter.
      - leere Kriterien -> on-topic behalten (lieber ein FP als eine echte
        Pflichtangabe verlieren).
    """
    crit_parts: list[str] = []
    for c in (pass_criteria or []):
        if c:
            crit_parts.append(str(c).lower())
    for c in (fail_criteria or []):
        if c:
            crit_parts.append(str(c).lower())
    if not crit_parts:
        return True
    crit_text = " ".join(crit_parts)
    hits: set[str] = set()
    for kws in BOOST_KEYWORDS.values():
        for kw in kws:
            if kw in crit_text:
                hits.add(kw)
                if len(hits) >= min_hits:
                    return True
    return False
