from dataclasses import dataclass
from typing import List, Dict
import re
from rapidfuzz import fuzz

CRITICAL_KEYWORDS = [
    "Rügefrist", "Garantie", "Gewährleistung", "Haftung", "Pönale",
    "Skonto", "Zahlungsbedingungen", "Preisänderung", "Teuerung", "SIA 122", "SIA 125"
]

class Criticality:
    NONE="none"; NORMAL="normal"; CRITICAL="critical"

def diff_ab_sections(base_text: str, offer_text: str) -> Dict:
    """
    Heuristik: wir chunk-en nach Überschriften / Absatzlänge, matchen best strings und flaggen,
    wenn Ähnlichkeit < Schwelle. Kritisch, wenn Keywords involviert sind.
    """
    base_chunks = _chunk(base_text)
    offer_chunks = _chunk(offer_text)
    changes = []; critical=[]
    for oc in offer_chunks:
        best = _best_match(oc, base_chunks)
        if best is None:
            ch = _mk_change("Neuer Absatz", oc, "?", Criticality.NORMAL)
            _route(ch, changes, critical); continue
        score = fuzz.token_set_ratio(oc, best)
        if score < 85:  # Schwelle justierbar
            crit = Criticality.CRITICAL if any(k.lower() in oc.lower() for k in CRITICAL_KEYWORDS) else Criticality.NORMAL
            ch = _mk_change("Geänderter Absatz", oc, "?", crit)
            _route(ch, changes, critical)
    reason = None
    if "unterschrift" in offer_text.lower() and "unterschrift" not in base_text.lower():
        reason = "signature_present"
    return {"changes": changes, "critical_changes": critical, "reason": reason}

def _chunk(text: str) -> List[str]:
    paras = re.split(r'\n{2,}', text)
    paras = [p.strip() for p in paras if p.strip()]
    return paras

def _best_match(needle: str, hay: List[str]):
    best = None; best_s = -1
    for h in hay:
        s = fuzz.token_set_ratio(needle, h)
        if s > best_s: best_s = s; best = h
    return best

def _mk_change(title: str, snippet: str, page: str, crit: str) -> Dict:
    return {"title": title, "snippet": snippet[:400], "page": page, "criticality": crit}

def _route(change, normal_list, critical_list):
    if change["criticality"] == Criticality.CRITICAL:
        critical_list.append(change)
    else:
        normal_list.append(change)
