"""Cookie-Policy-Agent Machine-Checks.

Pflichten an eine Cookie-Richtlinie nach TDDDG + DSGVO Art. 13 +
EuGH Planet49 + BGH Cookie-II:
  - Cookie-Kategorien benannt (essential / functional / analytics /
    marketing)
  - Pro Cookie: Name, Zweck, Speicherdauer, Empfänger/Vendor, Drittland
  - Opt-Out-Mechanik beschrieben + Banner-Reopen-Möglichkeit verlinkt
  - Versionsdatum / Stand
  - Drittland-Hinweise bei US-Transfer (Schrems II)
  - Verweis auf Browser-Einstellungen (Best-Practice)
  - Kontakt für Datenschutz (DSB oder verantwortliche Stelle)
"""

from __future__ import annotations

import re
from dataclasses import dataclass, field
from typing import Pattern


@dataclass(frozen=True)
class MC:
    mc_id: str
    field_id: str
    label: str
    norm: str
    patterns: tuple[Pattern[str], ...] = field(default_factory=tuple)
    severity_if_missing: str = "MEDIUM"
    # Eines der Patterns reicht (any) — default. False = ALLE müssen matchen
    require_all: bool = False


_CATEGORIES = (
    r"essenti(?:ell|al)|notwendig|technisch\s+notwendig|unbedingt\s+erforderlich",
    r"funktional|funktionelle?|preference|komfort",
    r"analyti(?:sch|cs)|statisti(?:k|sch)|leistung|performance",
    r"marketing|werbung|advertising|tracking|targeting",
)


MCS: tuple[MC, ...] = (
    MC(
        mc_id="CP-MC-001",
        field_id="categories_named",
        label="Cookie-Kategorien benannt (essential/functional/analytics/marketing)",
        norm="DSGVO Art. 13 + TDDDG § 25 (Transparenzpflicht)",
        severity_if_missing="HIGH",
        require_all=False,
        patterns=tuple(re.compile(p, re.IGNORECASE) for p in _CATEGORIES),
    ),
    MC(
        mc_id="CP-MC-002",
        field_id="purpose_described",
        label="Zweck pro Kategorie beschrieben",
        norm="DSGVO Art. 13 Abs. 1 lit. c (Zweck der Verarbeitung)",
        severity_if_missing="HIGH",
        patterns=(
            re.compile(r"\bzweck(?:e)?\b", re.IGNORECASE),
            re.compile(r"verwendet\s+wir", re.IGNORECASE),
            re.compile(r"dient\s+(?:zur?|dem|der|den)", re.IGNORECASE),
            re.compile(r"erm(?:ö|oe)glich(?:t|en)", re.IGNORECASE),
        ),
    ),
    MC(
        mc_id="CP-MC-003",
        field_id="retention_duration",
        label="Speicherdauer pro Cookie angegeben",
        norm="DSGVO Art. 13 Abs. 2 lit. a (Speicherdauer)",
        severity_if_missing="HIGH",
        patterns=(
            re.compile(r"\b(?:laufzeit|speicherdauer|dauer|gültig)",
                         re.IGNORECASE),
            re.compile(r"\b\d+\s*(?:tag|tage|monat|jahr|stunden|min)",
                         re.IGNORECASE),
            re.compile(r"session(?:-?cookie)?", re.IGNORECASE),
            re.compile(r"persistent(?:e|er)?", re.IGNORECASE),
        ),
    ),
    MC(
        mc_id="CP-MC-004",
        field_id="vendor_recipients",
        label="Empfänger/Vendoren genannt (Art. 13 Abs. 1 lit. e)",
        norm="DSGVO Art. 13 Abs. 1 lit. e (Empfänger)",
        severity_if_missing="HIGH",
        patterns=(
            re.compile(r"empf(?:ä|ae)nger|recipient", re.IGNORECASE),
            re.compile(r"dritt(?:e|er)\s+anbieter|drittanbieter|"
                         r"third[\-\s]?party", re.IGNORECASE),
            re.compile(r"\b(?:Google|Meta|Facebook|Microsoft|Hotjar|"
                         r"LinkedIn|Adobe|TikTok|Cloudflare|Akamai|"
                         r"Salesforce|HubSpot|Pinterest|Twitter|X\.com)\b",
                         re.IGNORECASE),
        ),
    ),
    MC(
        mc_id="CP-MC-005",
        field_id="opt_out_mechanism",
        label="Opt-Out-Mechanik dokumentiert",
        norm="DSGVO Art. 7 Abs. 3 (Widerruf der Einwilligung)",
        severity_if_missing="HIGH",
        patterns=(
            re.compile(r"opt[\-\s]?out|widerruf|widersprechen|"
                         r"abw(?:ä|ae)hlen|deaktivier",
                         re.IGNORECASE),
            re.compile(r"einstellungen\s+(?:[\wäöüÄÖÜ]+\s+)?"
                         r"(?:ä|ae)ndern|"
                         r"einwilligung\s+widerrufen|"
                         r"cookie[\-\s]?einstellungen?\b",
                         re.IGNORECASE),
        ),
    ),
    MC(
        mc_id="CP-MC-006",
        field_id="banner_reopen",
        label="Banner-Reopen / Cookie-Einstellungen-Link",
        norm="TDDDG § 25 (Symmetrie Annehmen/Ablehnen — Reopen Pflicht)",
        severity_if_missing="MEDIUM",
        patterns=(
            re.compile(r"cookie[\-\s]?einstellung(?:en)?\s+(?:ä|ae)ndern|"
                         r"cookie[\-\s]?einstellungen\s+(?:ö|oe)ffnen|"
                         r"einstellungen\s+anpassen|"
                         r"consent(?:[\-\s]?banner)?\s+(?:erneut|"
                         r"wieder)?\s*(?:ö|oe)ffnen|"
                         r"einwilligung\s+verwalten|"
                         r"cookie[\-\s]?pr(?:ä|ae)ferenzen",
                         re.IGNORECASE),
        ),
    ),
    MC(
        mc_id="CP-MC-007",
        field_id="version_date",
        label="Versionsdatum / Stand angegeben",
        norm="DSGVO Rechenschaftspflicht (Art. 5 Abs. 2)",
        severity_if_missing="MEDIUM",
        patterns=(
            re.compile(r"stand(?:\s+vom)?\s*[:\-]?\s*\d{1,2}",
                         re.IGNORECASE),
            re.compile(r"letzte\s+(?:aktualisierung|(?:ä|ae)nderung)",
                         re.IGNORECASE),
            re.compile(r"version\s*[:\-]?\s*\d", re.IGNORECASE),
            re.compile(r"g(?:ü|ue)ltig\s+ab\s+\d{1,2}", re.IGNORECASE),
        ),
    ),
    MC(
        mc_id="CP-MC-008",
        field_id="third_country_transfer",
        label="Drittland-Hinweis (Schrems-II / US-Transfer)",
        norm="DSGVO Art. 44 ff. + EuGH Schrems II",
        severity_if_missing="MEDIUM",
        patterns=(
            re.compile(r"dritt(?:land|staat)|USA?|vereinigte\s+staaten|"
                         r"international(?:e[rn]?)?\s+(?:transfer|"
                         r"daten(?:ü|ue)bermittlung)|"
                         r"(?:standardvertragsklauseln|SCC|"
                         r"angemessenheitsbeschluss|"
                         r"adequacy\s+decision|DPF|"
                         r"Data\s+Privacy\s+Framework)",
                         re.IGNORECASE),
        ),
    ),
    MC(
        mc_id="CP-MC-009",
        field_id="legal_basis",
        label="Rechtsgrundlage benannt (Art. 6 / § 25 TDDDG)",
        norm="DSGVO Art. 13 Abs. 1 lit. c + TDDDG § 25",
        severity_if_missing="MEDIUM",
        patterns=(
            re.compile(r"art\.?\s*6\s+(?:abs\.?\s*1\s+)?lit\.?\s*[a-f]",
                         re.IGNORECASE),
            re.compile(r"§\s*25\s+TDDDG", re.IGNORECASE),
            re.compile(r"rechtsgrundlage|einwilligung\s+(?:ist|liegt)|"
                         r"berechtigtes\s+interesse",
                         re.IGNORECASE),
        ),
    ),
    MC(
        mc_id="CP-MC-010",
        field_id="cookie_table_or_list",
        label="Cookie-Tabelle / Liste pro Cookie",
        norm="Best-Practice DSK + EDPB Guidelines 03/2022",
        severity_if_missing="MEDIUM",
        patterns=(
            # Konkrete Cookie-Namen oder typische Hosts
            re.compile(r"\b(?:_ga|_gid|_fbp|_fbc|_pk_id|"
                         r"OptanonConsent|JSESSIONID|cf_clearance|"
                         r"PHPSESSID|wp-settings|wordpress_logged_in)",
                         re.IGNORECASE),
            re.compile(r"<table|<tr|<td", re.IGNORECASE),
            re.compile(r"\|.*?\|.*?\|", re.IGNORECASE),  # markdown-Tabelle
        ),
    ),
    MC(
        mc_id="CP-MC-011",
        field_id="dpo_contact",
        label="Kontakt zum Datenschutzbeauftragten (DSB)",
        norm="DSGVO Art. 13 Abs. 1 lit. b (Kontaktdaten DSB)",
        severity_if_missing="MEDIUM",
        patterns=(
            re.compile(r"datenschutzbeauftragt|DSB|DPO",
                         re.IGNORECASE),
            re.compile(r"datenschutz[\-\s]?(?:team|kontakt|"
                         r"anfrag(?:e|en))",
                         re.IGNORECASE),
            re.compile(r"\bdatenschutz@", re.IGNORECASE),
        ),
    ),
    MC(
        mc_id="CP-MC-012",
        field_id="browser_settings_hint",
        label="Verweis auf Browser-Einstellungen (Cookies blockieren)",
        norm="Best-Practice — informierter Nutzer",
        severity_if_missing="LOW",
        patterns=(
            re.compile(r"browser[\-\s]?einstellung", re.IGNORECASE),
            re.compile(r"chrome|firefox|safari|edge", re.IGNORECASE),
            re.compile(r"cookies?\s+(?:l(?:ö|oe)schen|deaktivieren|"
                         r"blockieren)",
                         re.IGNORECASE),
        ),
    ),
)


MC_IDS: tuple[str, ...] = tuple(m.mc_id for m in MCS)
