"""
Gemeinsamer Report-Renderer.

EINE Quelle der Wahrheit für den Dateibericht (report.md) UND den E-Mail-Body.
So können Report und Alarm-Mail nicht mehr auseinanderlaufen. Alle Kommandos
enthalten das Target (direkt ausführbar); der angezeigte Score ist der bereits
aggregierte Gesamt-Score (Inhalt + KI + Zusatzprüfungen).
"""
from .plain import ampel, klartext_befunde, scanner_cmd, was_tun


def render_markdown(r: dict) -> str:
    a = r.get("assessment", {})
    d = r.get("diff", {})
    target = r.get("target", "")
    lvl = a.get("level", "green")
    level = lvl.upper()
    score = a.get("score", 0)
    level_badge = {"GREEN": "[OK]", "YELLOW": "[WARNUNG]", "RED": "[ALARM]"}.get(level, level)
    symbol, headline = ampel(lvl)
    ai = r.get("ai_result")

    config_path = r.get("config_path")
    scan_cmd = (f"python -m scanner --config {config_path} scan"
                if config_path else f"python -m scanner {target} scan")

    # ---- Klartext-Teil (für den Betreiber) ----
    lines = [
        f"# Prüfbericht für Ihre Website — {target or '?'}",
        "",
        f"**Erstellt:** {r.get('generated_at', '?')}  ",
        f"**Kommando:** `{scan_cmd}`",
        "",
        f"## {symbol} {headline}",
        "",
        "### Was bedeutet das?",
        "",
    ]
    for satz in klartext_befunde(d, r.get("cloak_diff"), r.get("asset_diff"),
                                 r.get("ext_links"), ai):
        lines.append(f"- {satz}")
    lines += ["", "### Was sollten Sie tun?", ""]
    for schritt in was_tun(lvl, target):
        lines.append(f"- {schritt}")

    # ---- Technischer Teil (für den Dienstleister) ----
    ai_funde = len(ai.get("findings", [])) if ai else 0
    ai_ungeprueft = len(ai.get("unchecked", [])) if ai else 0
    lines += [
        "",
        "---",
        "",
        "# Technische Details (für Ihren Dienstleister)",
        "",
        f"**Level:** {level_badge}  ",
        f"**Score:** {score}",
        "",
        "## Zusammenfassung",
        "",
        "| Kennzahl | Wert |",
        "|---|---|",
        f"| Geprüfte Seiten | {d.get('total_pages_checked', '?')} |",
        f"| Geänderte Seiten | {d.get('changed_pages', 0)} |",
        f"| Neue interne URLs | {len(d.get('new_internal_urls', []))} |",
        f"| Fehlende URLs | {len(d.get('missing_internal_urls', []))} |",
        f"| Neue externe Domains | {len(d.get('new_external_domains', []))} |",
        f"| Kaputte Links (neu) | {len(d.get('new_broken_urls', []))} |",
        f"| Kaputte Links (bekannt) | {len(d.get('known_broken_urls', []))} |",
        f"| Unerwartetes JSON-LD | {len(d.get('unexpected_jsonld', []))} |",
        f"| Verdächtige Dateinamen | {len(d.get('suspicious_filenames', []))} |",
        f"| KI-Funde (Text/Bild) | {ai_funde} |",
        f"| KI nicht geprüft | {ai_ungeprueft} |",
        f"| Whitelist-Verstösse | {len(r.get('whitelist_violations', []))} |",
        f"| Crawl-Fehler | {len(r.get('crawl_errors', []))} |",
        "",
        "## Risikobewertung",
        "",
    ]
    for reason in a.get("reasons", []):
        lines.append(f"- {reason}")
    if not a.get("reasons"):
        lines.append("- Keine Auffälligkeiten.")

    if d.get("new_external_domains"):
        lines += ["", "## Neue externe Domains", ""]
        for dom in d["new_external_domains"]:
            lines.append(f"- `{dom}`")

    if d.get("new_internal_urls"):
        lines += ["", "## Neue interne URLs", ""]
        for url in d["new_internal_urls"]:
            lines.append(f"- {url}")

    if d.get("missing_internal_urls"):
        lines += ["", "## Fehlende URLs (waren in Baseline)", ""]
        for url in d["missing_internal_urls"]:
            lines.append(f"- {url}")

    if d.get("page_diffs"):
        lines += ["", "## Geänderte Seiten", ""]
        for pd in d["page_diffs"]:
            lines += [f"### {pd['url']}", ""]
            if pd.get("added_chars"):
                lines.append(f"- Neuer Text: +{pd['added_chars']} Zeichen")
            if pd.get("meta_diff"):
                for field, change in pd["meta_diff"].items():
                    if isinstance(change, dict) and "old" in change:
                        lines.append(f"- {field}: `{change['old']}` → `{change['new']}`")
                    else:
                        lines.append(f"- {field}: {change}")
            if pd.get("canonical_changed"):
                lines.append(
                    f"- Canonical geändert: `{pd.get('old_canonical')}` → `{pd.get('new_canonical')}`"
                )
            if pd.get("new_hidden_content"):
                for h in pd["new_hidden_content"]:
                    lines.append(f"- Hidden Content ({h.get('type')}): `{', '.join(h.get('indicators', []))}`")
            if pd.get("new_meta_refresh"):
                for mr in pd["new_meta_refresh"]:
                    lines.append(f"- Meta-Refresh → `{mr}`")
            if pd.get("new_comment_links"):
                for cl in pd["new_comment_links"]:
                    lines.append(f"- Kommentar-Link: `{cl}`")
            if pd.get("new_inline_scripts"):
                for s in pd["new_inline_scripts"]:
                    lines.append(f"- Inline-Script: `{', '.join(s.get('patterns', []))}`")
            if pd.get("link_diff"):
                for ltype, ld in pd["link_diff"].items():
                    for added in ld.get("added", []):
                        lines.append(f"- {ltype} hinzugefügt: `{added}`")
                    for removed in ld.get("removed", []):
                        lines.append(f"- {ltype} entfernt: `{removed}`")
            if pd.get("text_diff"):
                lines += ["", "```diff"]
                lines += pd["text_diff"][:40]
                if len(pd["text_diff"]) > 40:
                    lines.append(f"... ({len(pd['text_diff']) - 40} weitere Zeilen)")
                lines.append("```")
            lines.append("")

    if d.get("new_pages_analysis"):
        lines += ["", "## Neue Seiten (Erstanalyse)", ""]
        for npa in d["new_pages_analysis"]:
            problems = (
                npa.get("hidden_content")
                or npa.get("inline_scripts")
                or npa.get("meta_refresh")
                or npa.get("unexpected_jsonld")
                or npa.get("comment_links")
            )
            flag = " [VERDAECHTIG]" if problems else ""
            lines.append(f"- {npa['url']}{flag}")

    new_broken = d.get("new_broken_urls", [])
    known_broken = d.get("known_broken_urls", [])
    if new_broken or known_broken:
        lines += ["", "## Kaputte Links", ""]
        for entry in new_broken:
            lines.append(f"- [NEU] HTTP {entry['status']} `{entry['url']}`")
            for page in entry.get("pages", [])[:3]:
                lines.append(f"  - gefunden auf: {page}")
        for entry in known_broken:
            lines.append(f"- [bekannt, noch nicht behoben] HTTP {entry['status']} `{entry['url']}`")
            for page in entry.get("pages", [])[:3]:
                lines.append(f"  - gefunden auf: {page}")

    if d.get("unexpected_jsonld"):
        lines += ["", "## Unerwartetes JSON-LD", ""]
        for entry in d["unexpected_jsonld"]:
            lines.append(f"- `{entry['url']}`: @type={entry['type']}")

    if d.get("suspicious_filenames"):
        lines += ["", "## Verdächtige Dateinamen", ""]
        for entry in d["suspicious_filenames"]:
            lines.append(f"- `{entry['page']}` → `{entry['url']}` ({entry['link_type']})")

    if r.get("whitelist_violations"):
        lines += ["", "## Whitelist-Verstösse", ""]
        for v in r["whitelist_violations"][:50]:
            lines.append(f"- [{v.get('type')}] {v.get('url', '')} (Domain: {v.get('domain', '')})")

    if r.get("missing_security_headers"):
        lines += ["", "## Fehlende Security-Header", ""]
        for url, hdrs in r["missing_security_headers"].items():
            for h in hdrs:
                lines.append(f"- `{url}`: {h}")

    if r.get("crawl_errors"):
        lines += ["", "## Crawl-Fehler", ""]
        for e in r["crawl_errors"][:20]:
            lines.append(f"- `{e.get('url', '?')}`: {e.get('error', '?')}")

    # ---- Ergebnisse der wöchentlichen Zusatzprüfungen (falls gelaufen) ----
    cd = r.get("cloak_diff")
    if cd is not None:
        lines += ["", "## Tarnungs-Prüfung (Cloaking)", ""]
        if cd.get("findings"):
            for f in cd["findings"]:
                lines.append(f"- `{f['url']}`")
                if f.get("extra_links"):
                    for link in f["extra_links"]:
                        lines.append(f"  - Nur für Google sichtbarer Link: `{link}`")
                if f.get("extra_text_chars", 0) > 50:
                    lines.append(f"  - Google sieht +{f['extra_text_chars']} Zeichen mehr Text")
                if f.get("vary_ua"):
                    lines.append("  - Server liefert je nach Besucher anderen Inhalt (Vary: User-Agent)")
        else:
            lines.append("- Keine Auffälligkeiten.")

    ad = r.get("asset_diff")
    if ad is not None:
        lines += ["", "## Datei-Prüfung (Bilder/Skripte/Stylesheets)", ""]
        if ad.get("changed"):
            for entry in ad["changed"]:
                size_info = f" ({entry['size_diff']:+d} Bytes)" if entry.get("size_diff") else ""
                lines.append(f"- Geändert [{entry['type']}]: `{entry['url']}`{size_info}")
        else:
            lines.append("- Keine Datei-Änderungen.")
        if ad.get("fetch_errors"):
            for entry in ad["fetch_errors"]:
                lines.append(f"- Nicht prüfbar: `{entry['url']}` ({entry['error']})")

    el = r.get("ext_links")
    if el is not None:
        lines += ["", "## Externe Links (Erreichbarkeit)", ""]
        lines.append(f"- Geprüft: {el.get('total', 0)}, kaputt: {el.get('broken', 0)}, "
                     f"nicht erreichbar: {el.get('errors', 0)}")
        for entry in el.get("broken_links", []):
            lines.append(f"- HTTP {entry['status']}: `{entry['url']}`")
            for page in entry.get("pages", [])[:3]:
                lines.append(f"  - gefunden auf: {page}")
        for entry in el.get("error_links", []):
            lines.append(f"- Nicht erreichbar: `{entry['url']}` ({entry.get('error', '?')})")
            for page in entry.get("pages", [])[:3]:
                lines.append(f"  - gefunden auf: {page}")

    if ai is not None:
        lines += ["", "## KI-Inhaltsanalyse", ""]
        if ai.get("skipped"):
            lines.append(f"- Übersprungen: {ai['skipped']}")
        else:
            lines.append(
                f"- {ai.get('checked', 0)} Inhalt(e) geprüft, "
                f"{ai.get('cache_hits', 0)} aus Cache, {ai.get('api_calls', 0)} API-Abfrage(n)."
            )
        if ai.get("unchecked"):
            lines.append(f"- ⚠ {len(ai['unchecked'])} Inhalt(e) **NICHT geprüft** "
                         "(KI-Dienst nicht erreichbar) — „nicht geprüft“ ≠ „sauber“:")
            for u in ai["unchecked"][:20]:
                ziel = u.get("asset_url") or u.get("url", "?")
                lines.append(f"  - [{u.get('kind', '?')}] `{ziel}`")
        for f in ai.get("findings", []):
            asset = f.get("asset_url")
            ziel = f"`{asset}` (auf {f['url']})" if asset else f"`{f['url']}`"
            lines.append(
                f"- [{f['kind']}] {ziel}: **{f['category']}** "
                f"(Schwere {f['severity']}, Konfidenz {f['confidence']:.0%})"
            )
            if f.get("explanation"):
                lines.append(f"  - Begründung: {f['explanation']}")
            if f.get("fingerprint"):
                lines.append("  - Quittieren bei Fehlalarm: "
                             f"`{scanner_cmd(target, 'ai-dismiss --hash ' + f['fingerprint'])}`")

    lines += ["", "---", "", "## Nächste Schritte", ""]
    lev = a.get("level", "green")
    if lev == "red":
        lines += [
            "1. **Sofort**: Website-Backend überprüfen, Dateien mit Backup vergleichen.",
            "2. Dienstleister kontaktieren.",
            f"3. Nach Bereinigung: `{scanner_cmd(target, 'approve --rebuild')}`",
        ]
    elif lev == "yellow":
        lines += [
            "1. Alle markierten URLs manuell prüfen.",
            f"2. Legitime Änderungen freigeben: `{scanner_cmd(target, 'approve --url <URL>')}`",
            f"3. Alle freigeben (wenn geprüft): `{scanner_cmd(target, 'approve --all')}`",
        ]
    else:
        lines += ["Keine Aktion erforderlich."]

    return "\n".join(lines) + "\n"
