"""
Action-Recipes — pro Finding-Typ eine umsetzbare Handlungsanweisung:
WAS tun, WARUM (Rechtsgrundlage), WIE formulieren (konkreter Textbaustein),
WO einfuegen (Doc-Abschnitt-Hinweis).

Ohne Recipes ist ein Finding nur eine Diagnose. Mit Recipe weiss der
Kunde sofort welchen Satz er an welche Stelle setzen muss.

Verwendung:
  from compliance.services.finding_action_recipes import recipe_for
  rec = recipe_for("no_cookies_listed")   # → dict mit what/why/fix_text/where/example
"""

from __future__ import annotations

from typing import TypedDict


class ActionRecipe(TypedDict, total=False):
    what: str          # 1-Satz Diagnose
    why: str           # Rechtsgrundlage / Risiko
    fix_text: str      # konkreter Textbaustein zum Einfuegen
    where: str         # in welchem Doc-Abschnitt
    example: str       # echtes Anwendungsbeispiel
    severity: str      # 'critical' | 'high' | 'medium' | 'low'


# ─── Vendor-/Cookie-Findings (im VVT-Block) ────────────────────────

VENDOR_FINDINGS: dict[str, ActionRecipe] = {

    "no_cookies_listed": {
        "what": "Anbieter ist erfasst, aber es sind keine konkreten Cookies "
                "dokumentiert.",
        "why": "Die DSK-Orientierungshilfe Telemedien 2024 fordert pro Anbieter "
               "eine Auflistung aller gesetzten Cookies mit Name + Zweck + "
               "Speicherdauer. 'Verwendet Cookies' ohne Details erfuellt "
               "Art. 13 Abs. 1 lit. e DSGVO nicht.",
        "fix_text": "Ergaenzen Sie pro Cookie eine Zeile mit folgenden Feldern:\n"
                    "  • Cookie-Name (z.B. _ga, _fbp, NID)\n"
                    "  • Setzender Anbieter (Firma + Sitzland)\n"
                    "  • Zweck (1 Satz, z.B. 'Reichweitenmessung pseudonym')\n"
                    "  • Speicherdauer (z.B. '2 Jahre', '24h', 'Session')",
        "where": "Cookie-Richtlinie unter dem Abschnitt 'Kategorien' "
                 "(Notwendig / Marketing / Statistik / ...).",
        "example": "_ga (Google Ireland Ltd.) — Statistik — eindeutige "
                   "Besucher-ID — Speicherdauer 2 Jahre",
        "severity": "high",
    },

    "no_country": {
        "what": "Anbieter-Sitzland ist nicht dokumentiert.",
        "why": "Art. 30 Abs. 1 lit. d DSGVO fordert die Kategorien der Empfaenger "
               "inkl. Sitz. Bei Drittland-Empfaengern (US, IN, CN ...) ist das "
               "zusaetzlich Pflicht nach Art. 13 Abs. 1 lit. f DSGVO.",
        "fix_text": "Fuegen Sie hinter dem Anbieternamen das Sitzland in "
                    "Klammern ein. Bei Drittland (ausserhalb EU/EWR) zusaetzlich "
                    "den Transfer-Mechanismus (SCC, DPF, Angemessenheitsbeschluss).",
        "where": "VVT-Eintrag bei 'Empfaenger' oder im Cookie-Anbieter-Listing.",
        "example": "Google Ireland Ltd., Dublin, Irland (EU). Bei US-Transfer: "
                   "'Google LLC, Mountain View, US — DPF-zertifiziert'.",
        "severity": "high",
    },

    "no_privacy_url": {
        "what": "Kein direkter Link zur Datenschutzerklaerung des Anbieters.",
        "why": "Art. 13 Abs. 2 lit. f DSGVO Transparenzgebot: der Nutzer muss "
               "die Datenverarbeitung beim Drittanbieter eigenverantwortlich "
               "nachvollziehen koennen.",
        "fix_text": "Ergaenzen Sie einen klickbaren Link zur Datenschutzerklaerung "
                    "des Anbieters direkt neben dem Anbieternamen.",
        "where": "Cookie-Richtlinie pro Vendor-Eintrag. Idealerweise als "
                 "letzter Spalteneintrag oder Inline-Link.",
        "example": "Google Analytics — Datenschutz: https://policies.google.com/privacy",
        "severity": "medium",
    },

    "broken_privacy_url": {
        "what": "Der angegebene Privacy-Link gibt einen Fehler zurueck "
                "(404 / 403 / Timeout).",
        "why": "Ein toter Link erfuellt Art. 13(2)(f) DSGVO nicht — die "
               "Transparenz-Pflicht laeuft ins Leere.",
        "fix_text": "1. Pruefen Sie den Link aus einem normalen Browser. "
                    "Funktioniert er dort? → Anbieter blockt automatisierte Pruefer (kein Mangel).\n"
                    "2. Funktioniert er nicht? → Aktualisieren Sie den Link in Ihrer "
                    "Cookie-Richtlinie auf die heute gueltige Privacy-URL des Anbieters.",
        "where": "Cookie-Richtlinie / Drittanbieter-Liste.",
        "example": "Wenn Adobe-Privacy-Link 404 gibt, ersetzen durch "
                   "https://www.adobe.com/privacy/policy.html",
        "severity": "high",
    },

    "no_opt_out_url": {
        "what": "Kein Opt-Out-Link fuer diesen Anbieter dokumentiert.",
        "why": "Art. 7 Abs. 3 DSGVO: der Widerruf der Einwilligung muss so "
               "einfach wie die Erteilung sein. Pro Drittanbieter muss eine "
               "Opt-Out-Moeglichkeit angeboten werden.",
        "fix_text": "Recherchieren Sie den offiziellen Opt-Out-Link des "
                    "Anbieters und ergaenzen Sie ihn. Falls Ihr Cookie-Banner "
                    "ein 'Einstellungen aendern' anbietet, ist das oft "
                    "ausreichend — der Link sollte trotzdem als Backup "
                    "dokumentiert sein.",
        "where": "Cookie-Richtlinie pro Vendor-Eintrag.",
        "example": "Google Analytics Opt-Out: https://tools.google.com/dlpage/gaoptout",
        "severity": "high",
    },

    "broken_opt_out": {
        "what": "Der angegebene Opt-Out-Link funktioniert nicht "
                "(404 / 403 / Timeout).",
        "why": "Art. 7(3) DSGVO Widerrufsmoeglichkeit ohne funktionierenden "
               "Link ist nicht gegeben.",
        "fix_text": "1. Pruefen Sie ob der Link aus einem Browser funktioniert. "
                    "403 kommt oft von Bot-Schutz und ist kein realer Mangel.\n"
                    "2. Bei echtem 404: aktualisieren Sie auf den heute gueltigen "
                    "Opt-Out-Link.\n"
                    "3. Alternativ verlinken Sie auf Ihren eigenen Cookie-Banner "
                    "'Einstellungen aendern'-Trigger.",
        "where": "Cookie-Richtlinie pro Vendor-Eintrag.",
        "example": "Wenn Criteo-Opt-Out 403 gibt, ist das oft Cloudflare-Schutz — "
                   "Link aus dem Browser klickbar → kein Mangel. Alternativ: "
                   "https://www.youronlinechoices.com/de/",
        "severity": "medium",
    },
}


# ─── Doc-Pruefungs-Findings (im DSE/Impressum/Cookie-Pruefblock) ───

DOC_CHECK_FINDINGS: dict[str, ActionRecipe] = {

    "Auftragsverarbeiter erwaehnt": {
        "what": "Auftragsverarbeiter (Hosting, CRM, Newsletter) sind nicht "
                "explizit erwaehnt + es fehlt Hinweis auf AVVs nach Art. 28 DSGVO.",
        "why": "Art. 28 DSGVO Auftragsverarbeitung erfordert dokumentierte AVVs. "
               "Art. 13(1)(e) DSGVO erfordert die Nennung der Empfaenger-"
               "Kategorien. Fehlt der Hinweis = klassischer Pruefpunkt der "
               "Aufsichtsbehoerden.",
        "fix_text": "Wir setzen sorgfaeltig ausgewaehlte Auftragsverarbeiter "
                    "(z.B. fuer Hosting, Webanalyse, Customer Service) ein. Mit "
                    "allen Auftragsverarbeitern haben wir Vertraege zur "
                    "Auftragsverarbeitung nach Art. 28 DSGVO geschlossen. Die "
                    "Auftragsverarbeiter handeln ausschliesslich auf unsere "
                    "Weisung und sind vertraglich zu angemessenen technischen "
                    "und organisatorischen Massnahmen verpflichtet.",
        "where": "Datenschutzerklaerung im Abschnitt 'Empfaenger' oder "
                 "'Datenuebermittlung'. Direkt nach der Aufzaehlung der "
                 "Empfaenger-Kategorien.",
        "example": "Empfaenger: BMW Niederlassungen, Vertragshaendler, "
                   "Auftragsverarbeiter (Cloud-Hosting AWS, CRM Salesforce, "
                   "Webanalyse Adobe Analytics — mit allen sind AVVs nach "
                   "Art. 28 DSGVO geschlossen).",
        "severity": "high",
    },

    "Automatisierte Entscheidungen / Profiling": {
        "what": "Keine Aussage zu automatisierten Einzelentscheidungen "
                "oder Profiling nach Art. 22 DSGVO.",
        "why": "Art. 13 Abs. 2 lit. f DSGVO: bei automatisierten "
               "Einzelentscheidungen muessen Logik, Tragweite und Auswirkungen "
               "erklaert werden. Bei KEINEM Profiling muss das explizit "
               "verneint werden — sonst lassen Aufsichtsbehoerden Unsicherheit "
               "offen.",
        "fix_text": "Variante A (kein Profiling):\n"
                    "  'Es findet keine automatisierte Entscheidungsfindung "
                    "im Sinne des Art. 22 DSGVO statt. Sofern wir Profiling "
                    "zur Anzeige personalisierter Inhalte einsetzen, erfolgt "
                    "dies ausschliesslich auf Basis Ihrer Einwilligung und "
                    "wird im Abschnitt [X] erlaeutert.'\n\n"
                    "Variante B (Profiling vorhanden, z.B. fuer Werbung):\n"
                    "  'Wir nutzen Profiling zur Anzeige personalisierter "
                    "Werbung. Die Logik basiert auf [Klick-Historie / "
                    "Besuchsverhalten / Praeferenzen]. Tragweite: "
                    "Anpassung der angezeigten Anzeigen. Auswirkung: keine "
                    "rechtlichen oder erheblichen Auswirkungen — Sie koennen "
                    "jederzeit widersprechen unter [Link/Kontakt].'",
        "where": "Datenschutzerklaerung am Ende des Abschnitts "
                 "'Betroffenenrechte' oder als eigener Absatz unter "
                 "'Automatisierte Entscheidungen'.",
        "example": "Standardformulierung Variante A — falls Sie KEIN Profiling "
                   "betreiben, ist das der sichere Default-Text.",
        "severity": "high",
    },

    "Konkrete Aufsichtsbehoerde benannt": {
        "what": "Aufsichtsbehoerde wird nicht namentlich genannt.",
        "why": "Art. 13(2)(d) DSGVO: das Beschwerderecht muss konkret "
               "kommuniziert werden — nicht 'die zustaendige Behoerde', sondern "
               "Name + Anschrift + Website.",
        "fix_text": "Sie haben das Recht, sich bei einer Datenschutz-"
                    "Aufsichtsbehoerde zu beschweren. Zustaendig ist:\n\n"
                    "  [Aufsichtsbehoerde mit Namen + Strasse + PLZ + Ort + Web]\n\n"
                    "Beispiel: 'Bayerisches Landesamt fuer Datenschutzaufsicht "
                    "(BayLDA), Promenade 18, 91522 Ansbach, www.lda.bayern.de'",
        "where": "Datenschutzerklaerung im Abschnitt 'Betroffenenrechte' oder "
                 "'Beschwerderecht'.",
        "example": "Fuer BMW AG (Sitz Muenchen, Bayern): BayLDA, Promenade 18, "
                   "91522 Ansbach, www.lda.bayern.de",
        "severity": "high",
    },

    "Angemessenheitsbeschluss der Kommission": {
        "what": "Drittlandtransfer erwaehnt, aber kein Hinweis auf den "
                "konkreten Angemessenheitsbeschluss / DPF / SCC.",
        "why": "Art. 13(1)(f) DSGVO: bei Drittlandtransfer muss der "
               "Transfer-Mechanismus benannt sein (Angemessenheitsbeschluss, "
               "Standardvertragsklauseln, BCR, Ausnahmen nach Art. 49).",
        "fix_text": "Fuer Datenuebermittlungen in die USA stuetzen wir uns auf "
                    "den Angemessenheitsbeschluss der EU-Kommission vom "
                    "10.07.2023 (EU-US Data Privacy Framework / DPF). Sofern "
                    "der Empfaenger DPF-zertifiziert ist, ist die Uebermittlung "
                    "rechtlich abgesichert. Bei nicht-zertifizierten Empfaengern "
                    "ergaenzen wir EU-Standardvertragsklauseln (SCC) gemaess "
                    "Durchfuehrungsbeschluss 2021/914.",
        "where": "Datenschutzerklaerung im Abschnitt 'Drittlandtransfer' oder "
                 "'Internationale Datenuebermittlung'.",
        "example": "Konkret: Google LLC (USA) ist DPF-zertifiziert "
                   "(Zertifikat einsehbar unter dataprivacyframework.gov).",
        "severity": "high",
    },

    "Anschrift des Verantwortlichen": {
        "what": "In der Cookie-Richtlinie fehlt die vollstaendige Anschrift.",
        "why": "Art. 13(1)(a) DSGVO: der Verantwortliche muss eindeutig "
               "identifizierbar sein. Cookie-Richtlinie + DSE muessen "
               "konsistente Angaben enthalten.",
        "fix_text": "Verantwortlich fuer die Datenverarbeitung im Sinne der "
                    "DSGVO ist:\n  [Firmenname]\n  [Strasse + Hausnummer]\n  "
                    "[PLZ + Ort]\n  [Land]\n  E-Mail: [...]",
        "where": "Cookie-Richtlinie am Anfang ODER Verweis-Link zur DSE.",
        "example": "Bayerische Motoren Werke Aktiengesellschaft, Petuelring 130, "
                   "80809 Muenchen, Deutschland",
        "severity": "high",
    },

    "Konkrete Cookie-Namen aufgelistet": {
        "what": "Cookies werden allgemein erwaehnt aber ohne konkrete Namen + "
                "Speicherdauer.",
        "why": "DSK-Orientierungshilfe Telemedien: Auflistung jedes einzelnen "
               "Cookies mit Name. Generische Aussagen ('wir nutzen "
               "Werbe-Cookies') sind unzureichend.",
        "fix_text": "Erweitern Sie die Cookie-Tabelle um die Spalten:\n"
                    "  Name | Anbieter | Zweck | Speicherdauer\n\n"
                    "Browser-Devtools (Application > Cookies) zeigt die "
                    "tatsaechlich gesetzten Namen — bitte Cookie-Liste "
                    "regelmaessig synchronisieren.",
        "where": "Cookie-Richtlinie im Abschnitt 'Verwendete Cookies'.",
        "example": "_ga | Google Ireland | Statistik (Besucher-ID) | 2 Jahre\n"
                   "_fbp | Meta Platforms IE | Werbung (Browser-ID) | 90 Tage",
        "severity": "high",
    },

    "Konkrete Speicherdauern pro Cookie": {
        "what": "Speicherdauer nur pauschal oder als generischer Bereich.",
        "why": "Art. 13(2)(a) DSGVO: konkrete Speicherdauer oder Kriterien "
               "fuer die Festlegung. DSK fordert Speicherdauer PRO Cookie.",
        "fix_text": "Pro Cookie eine konkrete Zeitangabe in der Cookie-Tabelle "
                    "ergaenzen: 'Session', '24 Stunden', '90 Tage', '2 Jahre'.",
        "where": "Cookie-Richtlinie in der Cookie-Tabelle.",
        "example": "JSESSIONID: Session — _ga: 2 Jahre — _fbp: 90 Tage",
        "severity": "high",
    },

    "Opt-Out-Links pro Drittanbieter": {
        "what": "Pro Drittanbieter ist kein direkter Opt-Out-Link angegeben.",
        "why": "Art. 7(3) DSGVO Widerrufsmoeglichkeit. EuGH Planet49 "
               "(C-673/17) bestaetigt: Widerruf muss so einfach wie Einwilligung sein.",
        "fix_text": "Pro Drittanbieter eine Spalte 'Opt-Out' ergaenzen mit "
                    "direktem Link. Alternativ: zentralen 'Cookie-"
                    "Einstellungen aendern'-Button im Footer der Webseite + "
                    "Hinweis darauf in der Cookie-Richtlinie.",
        "where": "Cookie-Richtlinie pro Vendor-Eintrag oder als zentraler "
                 "Abschnitt 'Wie kann ich widersprechen?'.",
        "example": "Google Analytics: https://tools.google.com/dlpage/gaoptout\n"
                   "Meta Pixel: ueber Facebook-Konto-Einstellungen",
        "severity": "high",
    },

    "Privacy-Policy-Links pro Drittanbieter": {
        "what": "Pro Drittanbieter ist kein direkter Datenschutz-Link gesetzt.",
        "why": "Art. 13(2)(f) DSGVO Transparenzgebot — Nutzer muss die "
               "Datenverarbeitung beim Drittanbieter eigenverantwortlich "
               "nachvollziehen koennen.",
        "fix_text": "Pro Drittanbieter Link auf dessen Datenschutzerklaerung "
                    "ergaenzen. Tabelle 'Anbieter | Datenschutz-Link'.",
        "where": "Cookie-Richtlinie im Drittanbieter-Listing.",
        "example": "Adobe Analytics: https://www.adobe.com/privacy/policy.html",
        "severity": "medium",
    },

    "Rechtswidriger Haftungsausschluss fuer Links": {
        "what": "Klassischer Link-Disclaimer ('Wir distanzieren uns von verlinkten "
                "Inhalten') ist im Impressum.",
        "why": "BGH I ZR 317/01: solche Disclaimer sind rechtlich wirkungslos. "
               "Sie befreien NICHT von der Stoererhaftung und koennen sogar "
               "den gegenteiligen Effekt haben (Anerkennung der eigenen "
               "Pruefpflicht).",
        "fix_text": "Entfernen Sie pauschale Link-Disclaimer vollstaendig aus "
                    "dem Impressum. Bei Bedarf ein knapper, zutreffender Satz:\n"
                    "  'Fuer den Inhalt verlinkter externer Webseiten ist "
                    "ausschliesslich deren Betreiber verantwortlich.'",
        "where": "Impressum am Ende des Dokuments.",
        "example": "Statt 'Wir distanzieren uns ausdruecklich von allen "
                   "Inhalten verlinkter Seiten' — einfach nichts schreiben.",
        "severity": "low",
    },

    "Verbraucherstreitbeilegung / OS-Plattform": {
        "what": "Kein Link zur EU-OS-Plattform bzw. keine Aussage zur "
                "Streitbeilegung.",
        "why": "Art. 14 EU-VO 524/2013 (B2C-Anbieter, Online-Verkauf): "
               "klickbarer Link auf https://ec.europa.eu/consumers/odr "
               "PFLICHT. §36 VSBG: Aussage ob teilnehmend oder nicht.",
        "fix_text": "Die EU-Kommission stellt eine Plattform zur Online-"
                    "Streitbeilegung (OS) bereit, die Sie unter "
                    "<a href='https://ec.europa.eu/consumers/odr'>"
                    "https://ec.europa.eu/consumers/odr</a> erreichen.\n\n"
                    "Wir sind nicht bereit oder verpflichtet, an "
                    "Streitbeilegungsverfahren vor einer "
                    "Verbraucherschlichtungsstelle teilzunehmen.",
        "where": "Impressum am Ende, eigener Abschnitt 'Streitbeilegung'.",
        "example": "Standardformulierung anwendbar fuer alle B2C-Anbieter ohne "
                   "ODR-Teilnahme.",
        "severity": "high",
    },

    "Name der vertretungsberechtigten Person": {
        "what": "Vertretungsberechtigte Person ist nicht namentlich mit "
                "Funktionsbezeichnung genannt.",
        "why": "§5 Abs. 1 Nr. 1 TMG: bei juristischen Personen sind die "
               "Vertretungsberechtigten namentlich zu nennen.",
        "fix_text": "Ergaenzen Sie nach der Firmenbezeichnung:\n"
                    "  'Vertreten durch: [Vorstand / Geschaeftsfuehrung] "
                    "[Vorname Nachname]'",
        "where": "Impressum direkt nach Firmenname + Anschrift.",
        "example": "Vertreten durch: Vorstandsvorsitzender Oliver Zipse",
        "severity": "high",
    },
}


def recipe_for(finding_key: str) -> ActionRecipe | None:
    """Lookup Recipe by finding-key. Vendors + Doc-Findings in einem Lookup."""
    if finding_key in VENDOR_FINDINGS:
        return VENDOR_FINDINGS[finding_key]
    if finding_key in DOC_CHECK_FINDINGS:
        return DOC_CHECK_FINDINGS[finding_key]
    # Fuzzy match auf Doc-Findings (label kann variieren)
    fk = finding_key.lower()
    for k, v in DOC_CHECK_FINDINGS.items():
        if k.lower() in fk or fk in k.lower():
            return v
    return None
