"""Kompakte Per-Engine-Projektion eines ConsentTestResult für die Browser-Matrix.

Die Matrix braucht NICHT die volle `/scan`-Antwort — nur die Felder, die je
Browser-Zeile angezeigt + persistiert werden: Cookies vor Consent / nach
Ablehnen, ob „Ablehnen" respektiert wurde, Oberflächen-Signale, Screenshot.
Bewusst schlank gehalten, damit der in `banner_result.browser_matrix` (JSONB)
persistierte Block klein bleibt — 6 Engines × voller Cookie-Liste + Screenshot
würde sonst schnell mehrere MB groß (BMW: ~780 Cookies je Phase).
"""

from __future__ import annotations

from typing import Any

# Cookie-Namen je Phase deckeln — die Matrix zeigt Zahlen + Beispiele, nicht
# die volle Liste (die steckt im textbasierten Cookie-Modul).
_NAME_CAP = 40
_TRACK_CAP = 20


def _vdict(v: Any) -> dict:
    """Violation (dataclass/obj/dict) → serialisierbares dict."""
    if isinstance(v, dict):
        return v
    return getattr(v, "__dict__", None) or {"text": str(v)}


def matrix_scan_dict(result: Any) -> dict:
    """`ConsentTestResult` → dict in der Form, die
    `multi_browser_scanner._extract_dimensions` liest (phases/banner_checks)
    plus ein kompakter `summary`-Block für Frontend + Persistenz.

    Defensiv via getattr — funktioniert auch, falls der Scanner mal ein
    bereits serialisiertes dict liefert (dann greifen die Defaults)."""
    before = list(getattr(result, "before_cookies", []) or [])
    after = list(getattr(result, "reject_cookies", []) or [])
    before_violations = list(getattr(result, "before_violations", []) or [])
    reject_violations = list(getattr(result, "reject_violations", []) or [])
    reject_new_tracking = list(getattr(result, "reject_new_tracking", []) or [])
    banner_text_violations = list(
        getattr(result, "banner_text_violations", []) or [])
    provider = getattr(result, "banner_provider", "") or ""

    summary = {
        "cookies_before_consent": len(before),
        "cookies_after_reject": len(after),
        "cookies_before_names": before[:_NAME_CAP],
        "cookies_after_reject_names": after[:_NAME_CAP],
        # „Ablehnen respektiert" = nach dem Klick auf „Ablehnen" keine Verstöße
        # UND kein neuer Tracker. Verbleibende essentielle Cookies (z.B. die
        # gespeicherte Consent-Entscheidung selbst) sind erlaubt → NICHT über
        # die reine Cookie-Zahl bewerten (sonst False Positive).
        "reject_respected": (len(reject_violations) == 0
                             and len(reject_new_tracking) == 0),
        "reject_new_tracking": reject_new_tracking[:_TRACK_CAP],
        "banner_detected": bool(getattr(result, "banner_detected", False)),
        "banner_provider": provider,
        "banner_screenshot_b64": getattr(result, "banner_screenshot_b64", "") or "",
        "surface": {
            "has_impressum_link": bool(
                getattr(result, "banner_has_impressum_link", False)),
            "has_dse_link": bool(
                getattr(result, "banner_has_dse_link", False)),
            "banner_text_issues": len(banner_text_violations),
        },
        # #62: Consent-Historie/Widerruf (Borlabs-Stil).
        "consent_history": getattr(result, "consent_history", {}) or {},
        # Oberflächen-Befunde je Engine (die 20 Banner-Checks: Button-Prominenz,
        # Toggle-Vorauswahl, Einleitungstext/Links …) — Text + Severity +
        # Norm-Bezug. Aggregierte Maßnahmen folgen im Cross-Finding.
        "banner_findings": [
            {"text": d.get("text", ""),
             "severity": d.get("severity", "MEDIUM"),
             "legal_ref": d.get("legal_ref", ""),
             "service": d.get("service", "")}
            for d in (_vdict(v) for v in banner_text_violations)
        ][:20],
        "violations": {
            "before_consent": len(before_violations),
            "after_reject": len(reject_violations),
            "banner_text": len(banner_text_violations),
        },
    }

    return {
        "banner_detected": bool(getattr(result, "banner_detected", False)),
        "banner_provider": provider,
        # Minimal-Form für _extract_dimensions (nur cookies-Listen + violations):
        "phases": {
            "before_consent": {"cookies": before},
            "after_reject": {"cookies": after},
        },
        "banner_checks": {
            "violations": [_vdict(v) for v in banner_text_violations],
        },
        "summary": summary,
    }
