<?php

function logUserAction($userId, $action, $details = null) {
    try {
        $db = Database::getInstance();
        $stmt = $db->prepare("INSERT INTO user_log (user_id, action, details) VALUES (?, ?, ?)");
        $stmt->execute([$userId, $action, $details]);
    } catch (Exception $e) {
        ErrorLogger::log("Fehler bei logUserAction: " . $e->getMessage());
    }
}

function logSettingChange($userId, $action, $settingKey = null, $details = null) {
    try {
        $db = Database::getInstance();
        $stmt = $db->prepare("INSERT INTO settings_log (user_id, action, setting_key, details) VALUES (?, ?, ?, ?)");
        $stmt->execute([$userId, $action, $settingKey, $details]);
    } catch (Exception $e) {
        ErrorLogger::log("Fehler bei logSettingChange: " . $e->getMessage());
    }
}


/**
 * FÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼hrt eine SQL-Anweisung mit optionalem Logging aus
 *
 * @param PDO $db Die Datenbankverbindung
 * @param string $sql Die SQL-Anweisung mit Platzhaltern
 * @param array $params Die zu bindenden Parameter
 * @param string $action Beschreibung des Vorgangs fÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼r das Log
 * @return PDOStatement Das ausgefÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼hrte Statement
 * @throws Exception Bei Fehler
 */
function executeWithLogging(PDO $db, string $sql, array $params, string $action = 'SQL-Aktion') {
    try {
        $stmt = $db->prepare($sql);
        $stmt->execute($params);

        // Erfolg loggen
        ErrorLogger::logSqlSuccess("$action erfolgreich. SQL: $sql | Parameter: " . json_encode($params));
        return $stmt;
    } catch (Exception $e) {
        // Fehler loggen
        ErrorLogger::logSqlError("$action fehlgeschlagen: " . $e->getMessage() . " | SQL: $sql | Parameter: " . json_encode($params));
        throw $e;
    }
}


function anonymizeIp(string $ip): string {
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
        return preg_replace('/\.\d+$/', '.0', $ip);
    }

    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
        return preg_replace('/:[a-fA-F0-9]+$/', ':0000', $ip);
    }

    return 'anonym'; // Fallback
}

function renderPageHelp(array $config): string
{
    $decodeText = static function (string $value): string {
        return html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
    };

    $title = trim($decodeText((string)($config['title'] ?? 'Kurzinfo')));
    $sections = $config['sections'] ?? [];
    $warning = trim($decodeText((string)($config['warning'] ?? '')));
    $open = !empty($config['open']);

    if (!is_array($sections) || $sections === []) {
        return '';
    }

    $html = '<details class="page-help" style="display:block;margin:1.25rem 0 2.75rem;border:1px solid #b9cfe6;border-left:5px solid #0d6efd;border-radius:12px;background:linear-gradient(180deg,#fbfdff 0%,#edf4fb 100%);box-shadow:0 10px 22px rgba(27,61,94,0.08);overflow:hidden;"' . ($open ? ' open' : '') . '>';
    $html .= '<summary style="display:flex;align-items:center;gap:0.75rem;padding:0.95rem 1.1rem;cursor:pointer;list-style:none;font-weight:600;color:#163b61;background:rgba(255,255,255,0.45);"><span class="page-help__icon" aria-hidden="true" style="display:inline-flex;align-items:center;justify-content:center;width:1.7rem;height:1.7rem;border-radius:999px;background:#0d6efd;color:#fff;font-size:1rem;font-weight:700;box-shadow:0 4px 10px rgba(13,110,253,0.2);flex:0 0 auto;">i</span><span class="page-help__title" style="letter-spacing:0.01em;">' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '</span></summary>';
    $html .= '<div class="page-help__body" style="padding:0.2rem 1.15rem 1.45rem;background:transparent;">';

    foreach ($sections as $section) {
        $heading = trim($decodeText((string)($section['heading'] ?? '')));
        $items = $section['items'] ?? [];
        if ($heading === '' || !is_array($items) || $items === []) {
            continue;
        }

        $html .= '<div class="page-help__section" style="margin-top:0.85rem;">';
        $html .= '<div class="page-help__heading" style="margin-bottom:0.35rem;font-weight:600;color:#163b61;">' . htmlspecialchars($heading, ENT_QUOTES, 'UTF-8') . '</div>';
        $html .= '<ul class="page-help__list" style="margin:0;padding-left:1.2rem;">';
        foreach ($items as $item) {
            $item = trim($decodeText((string)$item));
            if ($item === '') {
                continue;
            }
            $html .= '<li>' . htmlspecialchars($item, ENT_QUOTES, 'UTF-8') . '</li>';
        }
        $html .= '</ul>';
        $html .= '</div>';
    }

    if ($warning !== '') {
        $html .= '<div class="page-help__warning" style="margin-top:1rem;padding:0.8rem 0.95rem;border-left:4px solid #b7791f;background:#fff7e6;color:#6b4f16;border-radius:6px;"><strong>Wichtig:</strong> ' . htmlspecialchars($warning, ENT_QUOTES, 'UTF-8') . '</div>';
    }

    $html .= '</div>';
    $html .= '</details>';

    return $html;
}

function normalizeHelpLookupText(string $value): string
{
    $value = trim(mb_strtolower($value, 'UTF-8'));
    if ($value === '') {
        return '';
    }

    $value = str_replace(['ÃƒÆ’Ã‚Â¤', 'ÃƒÆ’Ã‚Â¶', 'ÃƒÆ’Ã‚Â¼', 'ÃƒÆ’Ã…Â¸', 'ÃƒÂ¢Ã¢â€šÂ¬Ã¢â‚¬Å“', 'ÃƒÂ¢Ã¢â€šÂ¬Ã¢â‚¬Â', '_'], ['ae', 'oe', 'ue', 'ss', '-', '-', ' '], $value);

    return preg_replace('/\s+/', ' ', $value) ?? $value;

}
function inferPageHelpPurpose(string $title, string $scriptName): string
{
    $titleKey = normalizeHelpLookupText($title);
    $scriptKey = normalizeHelpLookupText(pathinfo($scriptName, PATHINFO_FILENAME));
    $haystack = trim($titleKey . ' ' . $scriptKey);

    $purposeMap = [
        'dashboard' => 'Hier siehst du die wichtigsten Kennzahlen und Schnellzugriffe f&uuml;r den aktuellen Systemzustand.',
        'absender' => 'Hier verwaltest du Absenderdaten und legst fest, mit welchen Angaben E-Mails versendet werden.',
        'liste' => 'Hier verwaltest du Empf&auml;ngerlisten und ordnest Kontakte f&uuml;r Versand und Auswertungen.',
        'nutzer' => 'Hier verwaltest du Benutzerkonten, Rechte und nachvollziehbare Aktionen im Adminbereich.',
        'smtp' => 'Hier verwaltest du SMTP-Zug&auml;nge und pr&uuml;fst deren Einsatz f&uuml;r den Mailversand.',
        'kampagne' => 'Hier verwaltest du E-Mail-Kampagnen von der Vorbereitung bis zur Kontrolle des Versands.',
        'vorlage' => 'Hier verwaltest du E-Mail-Vorlagen als inhaltliche Grundlage f&uuml;r Kampagnen und Nachrichten.',
        'layout' => 'Hier verwaltest du Layouts f&uuml;r Aufbau und Gestaltung deiner E-Mails.',
        'empfaenger' => 'Hier verwaltest du Empf&auml;nger, deren Stammdaten und deren Zuordnung f&uuml;r den Versand.',
        'sperrliste' => 'Hier pflegst du gesperrte Empf&auml;nger oder Adressen, die nicht mehr angeschrieben werden d&uuml;rfen.',
        'tag' => 'Hier verwaltest du Tags, um Empf&auml;nger thematisch zu kennzeichnen und gezielt zu filtern.',
        'formular' => 'Hier verwaltest du Formulare f&uuml;r Anmeldung, Datenerfassung und Einbindung auf Webseiten.',
        'statistik' => 'Hier wertest du Versand-, &Ouml;ffnungs- und Klickdaten aus.',
        'pdf' => 'Hier verwaltest du PDF-Downloads und die dazugeh&ouml;rigen Dateien, Freigaben oder Auswertungen.',
        'testmail' => 'Hier verschickst du eine Testmail, um Inhalte und Versandweg vor dem Live-Einsatz zu pr&uuml;fen.',
        'rotation' => 'Hier pr&uuml;fst du die SMTP-Rotation und kontrollierst, wie Versandkonten nacheinander genutzt werden.',
        'reset' => 'Hier verwaltest du Passwort-Zur&uuml;cksetzungen oder f&uuml;hrst sie f&uuml;r einen Benutzer durch.',
        'login' => 'Hier meldest du dich an oder pr&uuml;fst Anmeldeereignisse und fehlgeschlagene Zugriffe.',
        'settings' => 'Hier verwaltest du zentrale Systemeinstellungen f&uuml;r Verhalten, Versand und Administration.',
        'einstellung' => 'Hier verwaltest du zentrale Systemeinstellungen f&uuml;r Verhalten, Versand und Administration.',
        'status' => 'Hier kontrollierst du den aktuellen Versand- oder Systemstatus und erkennst Auff&auml;lligkeiten fr&uuml;hzeitig.',
        'monitor' => 'Hier &uuml;berwachst du Zust&auml;nde, Ereignisse oder Reaktionen rund um den Mailversand.',
        'bounce' => 'Hier pr&uuml;fst du Bounce-Ereignisse und deren systematische Verarbeitung.',
        'blacklist' => 'Hier pflegst du gesperrte Empf&auml;nger oder Adressen, die nicht mehr angeschrieben werden d&uuml;rfen.',
        'transaktions' => 'Hier verwaltest oder startest Transaktionsmails f&uuml;r konkrete Einzelereignisse.',
        'optin' => 'Hier pr&uuml;fst du den Double-Opt-in-Status und zugeh&ouml;rige Detailinformationen.',
        'import' => 'Hier importierst du Daten oder pr&uuml;fst den Verlauf bereits ausgef&uuml;hrter Importe.',
        'log' => 'Hier pr&uuml;fst du protokollierte Vorg&auml;nge, &Auml;nderungen oder Fehler zur Nachverfolgung.',
    ];

    foreach ($purposeMap as $needle => $description) {
        if ($needle !== '' && str_contains($haystack, $needle)) {
            return $description;
        }
    }

    if ($title !== '') {
        return 'Hier arbeitest du im Bereich "' . $title . '" und f&uuml;hrst die daf&uuml;r vorgesehenen Aktionen aus.';
    }

    return 'Hier arbeitest du in diesem Bereich und f&uuml;hrst die daf&uuml;r vorgesehenen Aktionen aus.';

}
function inferPageHelpActionHint(string $title, string $pageContent = '', string $scriptName = ''): string
{
    $titleKey = normalizeHelpLookupText($title);
    $scriptKey = normalizeHelpLookupText(pathinfo($scriptName, PATHINFO_FILENAME));
    $contentKey = normalizeHelpLookupText($pageContent);
    $haystack = ' ' . trim($titleKey . ' ' . $scriptKey . ' ' . $contentKey) . ' ';

    if (str_contains($haystack, ' loeschen ') || str_contains($haystack, ' delete ')) {
        return 'Pr&uuml;fe vor dem Best&auml;tigen genau, ob du den richtigen Eintrag ausgew&auml;hlt hast.';
    }

    if (str_contains($haystack, ' bearbeiten ') || str_contains($haystack, ' edit ')) {
        return 'Vorhandene Daten werden erst durch Speichern aktualisiert.';
    }

    if (str_contains($haystack, ' neu ') || str_contains($haystack, ' erstellen ') || str_contains($haystack, ' anlegen ') || str_contains($haystack, ' create ') || str_contains($haystack, ' upload ')) {
        return 'Lege neue Daten vollst&auml;ndig an, damit Folgeprozesse ohne Nacharbeit funktionieren.';
    }

    if (str_contains($haystack, ' log ') || str_contains($haystack, ' verlauf ')) {
        return 'Nutze Filter und Zeitr&auml;ume, um relevante Vorg&auml;nge schneller einzugrenzen.';
    }

    if (str_contains($haystack, ' statistik ') || str_contains($haystack, ' monitor ') || str_contains($haystack, ' status ')) {
        return 'Vergleiche Kennzahlen und Statuswerte immer im fachlichen Kontext des betroffenen Versands.';
    }

    if (str_contains($haystack, ' login ') || str_contains($haystack, ' passwort ')) {
        return 'Achte darauf, sicherheitsrelevante Hinweise und ungew&ouml;hnliche Zugriffsmuster zeitnah zu pr&uuml;fen.';
    }

    if (str_contains($haystack, ' import ')) {
        return 'Kontrolliere Dateiformat, Feldzuordnung und Ergebnisprotokoll vor und nach dem Import.';
    }

    return 'Nutze die Aktionen auf dieser Seite nur f&uuml;r den Vorgang, den du gerade tats&auml;chlich durchf&uuml;hren willst.';

}

function buildDefaultPageHelp(string $title, string $pageContent = '', string $scriptName = ''): string
{
    $title = trim($title);
    $content = strtolower($pageContent);
    $scriptName = strtolower($scriptName);

    $hasGetForm = str_contains($content, '<form method="get"') || str_contains($content, 'filterform') || str_contains($content, 'name="search"');
    $hasPostForm = str_contains($content, '<form method="post"') || (str_contains($content, '<form ') && !$hasGetForm);
    $isLogPage = str_contains($scriptName, 'log') || str_contains($title, 'log');
    $isListPage = str_contains($title, 'liste') || str_contains($title, 'kampagne') || str_contains($title, 'vorlage') || str_contains($title, 'formular');
    $purpose = inferPageHelpPurpose($title, $scriptName);
    $actionHint = inferPageHelpActionHint($title, $pageContent, $scriptName);

    if ($hasPostForm) {
        return renderPageHelp([
            'sections' => [
                [
                    'heading' => 'Was macht diese Seite?',
                    'items' => [
                        $purpose,
                        'Die Eingaben werden erst nach dem Speichern &uuml;bernommen.',
                    ],
                ],
                [
                    'heading' => 'Was muss ich eingeben oder ausw&auml;hlen?',
                    'items' => [
                        'F&uuml;lle nur die Felder aus, die f&uuml;r diese Aktion wirklich ben&ouml;tigt werden.',
                        'Pr&uuml;fe vor dem Speichern, ob Auswahl und Werte fachlich zusammenpassen.',
                    ],
                ],
                [
                    'heading' => 'Worauf sollte ich achten?',
                    'items' => [
                        $actionHint,
                        'Kontrolliere wichtige Angaben vor dem Speichern noch einmal.',
                    ],
                ],
            ],
        ]);
    }

    if ($hasGetForm) {
        return renderPageHelp([
            'sections' => [
                [
                    'heading' => 'Was macht diese Seite?',
                    'items' => [
                        $purpose,
                        'Die Auswahl &auml;ndert nur die Ansicht und nicht die gespeicherten Daten.',
                    ],
                ],
                [
                    'heading' => 'Was muss ich eingeben oder ausw&auml;hlen?',
                    'items' => [
                        'Setze nur die Filter, die du f&uuml;r die aktuelle Auswertung brauchst.',
                        'Leere oder zur&uuml;ckgesetzte Filter zeigen wieder den breiteren Datenbestand.',
                    ],
                ],
                [
                    'heading' => 'Worauf sollte ich achten?',
                    'items' => [
                        $actionHint,
                        'Pr&uuml;fe die aktuelle Auswahl, wenn Ergebnisse fehlen oder unerwartet klein sind.',
                    ],
                ],
            ],
        ]);
    }

    if ($isLogPage) {
        return renderPageHelp([
            'sections' => [
                [
                    'heading' => 'Was macht diese Seite?',
                    'items' => [
                        $purpose,
                        'Die Ansicht dient zur Kontrolle und Nachverfolgung.',
                    ],
                ],
                [
                    'heading' => 'Was muss ich eingeben oder ausw&auml;hlen?',
                    'items' => [
                        'Nutze vorhandene Such- oder Filterm&ouml;glichkeiten, um den relevanten Zeitraum oder Bereich einzugrenzen.',
                    ],
                ],
                [
                    'heading' => 'Worauf sollte ich achten?',
                    'items' => [
                        $actionHint,
                        'Nicht jede Warnung bedeutet automatisch einen kritischen Fehler.',
                    ],
                ],
            ],
        ]);
    }

    if ($isListPage || $title !== '') {
        return renderPageHelp([
            'sections' => [
                [
                    'heading' => 'Was macht diese Seite?',
                    'items' => [
                        $purpose,
                        'Je nach Seite kannst du Eintr&auml;ge pr&uuml;fen, &ouml;ffnen oder weitere Aktionen starten.',
                    ],
                ],
                [
                    'heading' => 'Was muss ich eingeben oder ausw&auml;hlen?',
                    'items' => [
                        'Nutze vorhandene Schaltfl&auml;chen, Suchfelder oder Filter nur f&uuml;r die Aktion, die du gerade brauchst.',
                    ],
                ],
                [
                    'heading' => 'Worauf sollte ich achten?',
                    'items' => [
                        $actionHint,
                    ],
                ],
            ],
        ]);
    }

    return '';

}
function renderCustomFormField(array $field): string
{
    $fieldKey = (string) ($field['field_key'] ?? '');
    $label = (string) ($field['label'] ?? $fieldKey);
    $fieldType = (string) ($field['field_type'] ?? 'text');
    $isRequired = !empty($field['is_required']);

    if ($fieldKey === '') {
        return '';
    }

    $safeKey = htmlspecialchars($fieldKey, ENT_QUOTES, 'UTF-8');
    $safeLabel = htmlspecialchars($label, ENT_QUOTES, 'UTF-8');
    $requiredAttr = $isRequired ? ' required' : '';

    if ($fieldType === 'checkbox') {
        return <<<HTML
    <div class="mr9-field mr9-field-checkbox">
      <div class="mr9-check">
        <input type="checkbox" name="{$safeKey}" id="{$safeKey}" value="1"{$requiredAttr}>
        <label for="{$safeKey}">{$safeLabel}</label>
      </div>
    </div>
HTML;
    }

    $htmlInputType = in_array($fieldType, ['date', 'number'], true) ? $fieldType : 'text';

    return <<<HTML
    <div class="mr9-field">
      <label for="{$safeKey}">{$safeLabel}:</label>
      <input type="{$htmlInputType}" name="{$safeKey}" id="{$safeKey}"{$requiredAttr}>
    </div>
HTML;
}

function getDefaultFieldTooltipMap(): array
{
    return [
        '#name' => 'Interner Name f&uuml;r diesen Eintrag.',
        '[name="name"]' => 'Interner Name f&uuml;r diesen Eintrag.',
        '#description' => 'Kurze interne Beschreibung zur besseren Einordnung.',
        '[name="description"]' => 'Kurze interne Beschreibung zur besseren Einordnung.',
        '#email' => 'G&uuml;ltige E-Mail-Adresse f&uuml;r diesen Vorgang.',
        '[name="email"]' => 'G&uuml;ltige E-Mail-Adresse f&uuml;r diesen Vorgang.',
        '[name="empfaenger"]' => 'Empf&auml;ngeradresse f&uuml;r Test oder Einzelvorgang.',
        '#password' => 'Passwort entsprechend den aktuellen Vorgaben eingeben.',
        '[name="password"]' => 'Passwort entsprechend den aktuellen Vorgaben eingeben.',
        '#confirm' => 'Passwort zur Best&auml;tigung noch einmal eingeben.',
        '[name="confirm"]' => 'Passwort zur Best&auml;tigung noch einmal eingeben.',
        '#subject' => 'Betreff der E-Mail, wie er sp&auml;ter angezeigt wird.',
        '[name="subject"]' => 'Betreff der E-Mail, wie er sp&auml;ter angezeigt wird.',
        '#editor' => 'Inhalt der Nachricht oder Vorlage im HTML-Format.',
        '[name="body_html"]' => 'Inhalt der Nachricht oder Vorlage im HTML-Format.',
        '#layout_id' => 'Optionales Layout f&uuml;r Kopf- und Fu&szlig;bereich.',
        '[name="layout_id"]' => 'Optionales Layout f&uuml;r Kopf- und Fu&szlig;bereich.',
        '#from_identity_id' => 'Absender, der f&uuml;r diese Liste oder Nachricht verwendet wird.',
        '[name="from_identity_id"]' => 'Absender, der f&uuml;r diese Liste oder Nachricht verwendet wird.',
        '#requires_doi' => 'Aktivieren, wenn Anmeldungen erst nach Best&auml;tigung g&uuml;ltig sein sollen.',
        '[name="requires_doi"]' => 'Aktivieren, wenn Anmeldungen erst nach Best&auml;tigung g&uuml;ltig sein sollen.',
        '#notify_on_signup' => 'Interne Benachrichtigung bei neuer Formular-Anmeldung.',
        '[name="notify_on_signup"]' => 'Interne Benachrichtigung bei neuer Formular-Anmeldung.',
        '[name="anrede"]' => 'Optionale pers&ouml;nliche Anrede.',
        '[name="vorname"]' => 'Vorname des Empf&auml;ngers oder Kontakts.',
        '[name="nachname"]' => 'Nachname des Empf&auml;ngers oder Kontakts.',
        '[name="status"]' => 'Aktueller fachlicher Status des Eintrags.',
        '#list_id' => 'Ziel-Liste f&uuml;r diese Aktion oder Zuordnung.',
        '[name="list_id"]' => 'Ziel-Liste f&uuml;r diese Aktion oder Zuordnung.',
        '[name="liste_id"]' => 'Ziel-Liste f&uuml;r diese Aktion oder Zuordnung.',
        '[name="tags[]"]' => 'Mehrere Tags zur fachlichen Kennzeichnung ausw&auml;hlen.',
        '[name="tags"]' => 'Tag oder Tag-Auswahl f&uuml;r Segmentierung und Kennzeichnung.',
        '[name="field_key"]' => 'Technischer Schl&uuml;ssel des Feldes. M&ouml;glichst stabil lassen.',
        '[name="label"]' => 'Bezeichnung, die im Formular oder in der Verwaltung angezeigt wird.',
        '[name="field_type"]' => 'Legt fest, welche Art Eingabe dieses Feld verwendet.',
        '[name="is_required"]' => 'Markiert das Feld als Pflichtangabe.',
        '[name="pdf_file"]' => 'PDF-Datei, die f&uuml;r den gesch&uuml;tzten Download verwendet wird.',
        '[name="title"]' => 'Interner Titel f&uuml;r die sp&auml;tere Zuordnung und Anzeige.',
        '[name="valid_hours"]' => 'G&uuml;ltigkeitsdauer in Stunden ab jetzt.',
        '[name="renew_token"]' => 'Erzeugt einen neuen Token und macht &auml;ltere Links ung&uuml;ltig.',
        '[name="absender"]' => 'Absenderidentit&auml;t f&uuml;r diesen Versand.',
        '[name="smtp"]' => 'SMTP-Konto, &uuml;ber das die E-Mail gesendet wird.',
        '[name="template_id"]' => 'Vorlage, die f&uuml;r Inhalt und Betreff verwendet wird.',
        '[name="campaign_type"]' => 'Legt fest, ob die Kampagne nach Datum, Follow-up oder transaktional arbeitet.',
        '[name="schedule_at"]' => 'Geplanter Versandzeitpunkt f&uuml;r datumsbasierte Kampagnen.',
        '[name="followup_days"]' => 'Anzahl Tage bis zum Versand im Follow-up-Ablauf.',
        '[name="priority"]' => 'Versandpriorit&auml;t innerhalb der Queue.',
        '[name="use_doi_only"]' => 'Begrenzt den Versand auf best&auml;tigte Empf&auml;nger, wenn aktiviert.',
        '[name="redirect_url"]' => 'Optionale Ziel-URL direkt nach dem Absenden.',
        '[name="redirect_url_confirm"]' => 'Optionale Ziel-URL nach Best&auml;tigung des Eintrags.',
        '[name="lists[]"]' => 'Auswahl der Listen, die mit diesem Formular verbunden sind.',
        '[name="felder[]"]' => 'Zusatzfelder, die im Formular angezeigt werden sollen.',
        '[name="show_anrede"]' => 'Blendet das Feld Anrede im Formular ein.',
        '[name="show_vorname"]' => 'Blendet das Feld Vorname im Formular ein.',
        '[name="show_nachname"]' => 'Blendet das Feld Nachname im Formular ein.',
        '[name="require_vorname"]' => 'Macht den Vornamen im Formular zur Pflichtangabe.',
        '[name="require_nachname"]' => 'Macht den Nachnamen im Formular zur Pflichtangabe.',
        '[name="success_message"]' => 'Text, der nach erfolgreichem Absenden angezeigt wird.',
        '[name="dkim_selector"]' => 'DKIM-Selector des sendenden Systems, falls DKIM verwendet wird.',
        '[name="dkim_private_key"]' => 'Privater DKIM-Schl&uuml;ssel im PEM-Format f&uuml;r die Signierung ausgehender E-Mails.',
        '[name="is_active"]' => 'Aktiviert oder deaktiviert diesen Datensatz f&uuml;r die weitere Nutzung.',
        '[name="smtp_host"]' => 'Hostname des SMTP-Servers.',
        '[name="smtp_user"]' => 'Benutzername f&uuml;r die Anmeldung am SMTP-Server.',
        '[name="smtp_pass"]' => 'Passwort f&uuml;r die Anmeldung am SMTP-Server.',
        '[name="smtp_port"]' => 'Port des SMTP-Servers, zum Beispiel 587 oder 465.',
        '[name="smtp_secure"]' => 'Verschl&uuml;sselung f&uuml;r die SMTP-Verbindung, zum Beispiel TLS oder SSL.',
        '[name="smtp_email"]' => 'Technische Return-Path- oder Versandadresse dieses SMTP-Zugangs.',
        '[name="max_per_20min"]' => 'Maximale Anzahl Nachrichten f&uuml;r diese Domain-Regel innerhalb von 20 Minuten.',
        '[name="max_global_20min"]' => 'Globale Obergrenze f&uuml;r dieses SMTP-Konto innerhalb von 20 Minuten.',
        '[name="domain"]' => 'Domain, f&uuml;r die diese Regel oder Einschr&auml;nkung gilt.',
        '[name="setting_key"]' => 'Technischer Schl&uuml;ssel dieser Einstellung.',
        '[name="setting_value"]' => 'Wert, der f&uuml;r diese Einstellung gespeichert werden soll.',
        '[name="user_id"]' => 'Interne Benutzer-ID f&uuml;r diesen Vorgang.',
        '[name="username"]' => 'Interner Benutzername f&uuml;r die Anmeldung oder Verwaltung.',
        '[name="user_name"]' => 'Interner Benutzername f&uuml;r die Anmeldung oder Verwaltung.',
        '[name="password_confirm"]' => 'Passwort zur zus&auml;tzlichen Best&auml;tigung erneut eingeben.',
        '[name="role"]' => 'Berechtigungsrolle f&uuml;r diesen Benutzer.',
        '[name="admin_role"]' => 'Berechtigungsrolle f&uuml;r diesen Administrator.',
        '[name="token"]' => 'Technischer Token f&uuml;r diesen Vorgang.',
        '[name="confirm_url"]' => 'Best&auml;tigungslink oder technischer Verweis f&uuml;r Double-Opt-In.',
        '[name="custom[]"]' => 'Zusatzwerte f&uuml;r benutzerdefinierte Felder.',
        '[name^="custom["]' => 'Zusatzwert f&uuml;r dieses benutzerdefinierte Feld.',
        '[name="filter_type"]' => 'Legt fest, nach welchem Kriterium die Auswahl eingeschr&auml;nkt wird.',
        '[name="filter_value"]' => 'Wert f&uuml;r die ausgew&auml;hlte Filterart.',
        '[name="tag_id"]' => 'Tag zur Segmentierung oder Zuordnung.',
        '[name="tag_mode"]' => 'Legt fest, ob ein Tag ein- oder ausgeschlossen wird.',
        '[name="list_id[]"]' => 'Mehrfachauswahl der Ziel-Listen f&uuml;r diesen Vorgang.',
        '[name="file_name"]' => 'Dateiname oder interne Bezeichnung f&uuml;r diese Datei.',
        '[name="search"]' => 'Suchbegriff zur Eingrenzung der aktuellen Ansicht.',
        '[name="file"]' => 'Datei f&uuml;r Import oder Upload in diesem Bereich.',
        '[name="csv_file"]' => 'CSV-Datei f&uuml;r den Import in die ausgew&auml;hlte Liste.',
        '[name="csrf_token"]' => 'Technisches Schutzfeld gegen unerlaubte Formularaufrufe.',
        '[name="settings[worker_max_emails]"]' => 'Maximale Anzahl E-Mails pro Worker-Lauf.',
        '[name="settings[worker_max_runtime]"]' => 'Maximale Laufzeit eines Worker-Durchlaufs in Sekunden.',
        '[name="settings[worker_sleep_us]"]' => 'Pause zwischen einzelnen Versandvorg&auml;ngen in Mikrosekunden.',
    ];
}

function renderFieldTooltipBootstrap(array $extraTooltips = []): string
{
    $tooltips = array_merge(getDefaultFieldTooltipMap(), $extraTooltips);
    if ($tooltips === []) {
        return '';
    }

    $tooltips = array_map(
        static fn($text) => html_entity_decode((string) $text, ENT_QUOTES | ENT_HTML5, 'UTF-8'),
        $tooltips
    );

    $json = json_encode($tooltips, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    if (!is_string($json)) {
        return '';
    }

    return '<script>'
        . '(function(){'
        . 'const tooltipMap=' . $json . ';'
        . 'const applyTooltips=function(){'
        . 'Object.entries(tooltipMap).forEach(([selector,text])=>{'
        . 'document.querySelectorAll(selector).forEach((el)=>{'
        . 'if(!el||el.dataset.tooltipBound==="1"){return;}'
        . 'if(!el.getAttribute("title")){el.setAttribute("title",text);}'
        . 'el.setAttribute("data-bs-toggle","tooltip");'
        . 'el.setAttribute("data-bs-placement","top");'
        . 'el.setAttribute("data-bs-trigger","hover focus");'
        . 'el.dataset.tooltipBound="1";'
        . '});'
        . '});'
        . 'if(window.bootstrap&&bootstrap.Tooltip){'
        . 'document.querySelectorAll(\'[data-bs-toggle="tooltip"]\').forEach((el)=>{'
        . 'bootstrap.Tooltip.getOrCreateInstance(el);'
        . '});'
        . '}'
        . '};'
        . 'if(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",applyTooltips);}else{applyTooltips();}'
        . '})();'
        . '</script>';
}

function fetchScalarInt(PDO $db, string $sql, array $params = []): int
{
    $stmt = $db->prepare($sql);
    $stmt->execute($params);

    return (int) $stmt->fetchColumn();
}

function getSystemSetupStatus(PDO $db): array
{
    $counts = [
        'active_senders' => 0,
        'active_smtp' => 0,
        'lists_total' => 0,
        'lists_ready' => 0,
        'lists_without_sender' => 0,
        'templates_total' => 0,
        'forms_total' => 0,
        'forms_invalid_list' => 0,
        'recipients_total' => 0,
        'campaigns_total' => 0,
        'campaigns_scheduled' => 0,
        'campaigns_invalid_template' => 0,
    ];
    $warnings = [];

    try {
        $counts['active_senders'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM sender_identities WHERE is_active = 1');
        $counts['active_smtp'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM smtp_accounts WHERE is_active = 1');
        $counts['lists_total'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM lists');
        $counts['lists_ready'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM lists l JOIN sender_identities s ON s.id = l.from_identity_id AND s.is_active = 1');
        $counts['lists_without_sender'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM lists l LEFT JOIN sender_identities s ON s.id = l.from_identity_id AND s.is_active = 1 WHERE s.id IS NULL');
        $counts['templates_total'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM email_templates');
        $counts['forms_total'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM forms');
        $counts['forms_invalid_list'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM forms f LEFT JOIN lists l ON l.id = f.list_id WHERE l.id IS NULL');
        $counts['recipients_total'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM recipients');
        $counts['campaigns_total'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM campaigns');
        $counts['campaigns_scheduled'] = fetchScalarInt($db, "SELECT COUNT(*) FROM campaigns WHERE status = 'scheduled'");
        $counts['campaigns_invalid_template'] = fetchScalarInt($db, 'SELECT COUNT(*) FROM campaigns c LEFT JOIN email_templates t ON t.id = c.template_id WHERE t.id IS NULL');
    } catch (Throwable $e) {
        ErrorLogger::logSqlError('Systemstatus konnte nicht geladen werden | error: ' . $e->getMessage());
    }

    if ($counts['active_senders'] === 0) {
        $warnings[] = 'Es ist noch kein aktiver Absender vorhanden.';
    }
    if ($counts['active_smtp'] === 0) {
        $warnings[] = 'Es ist noch kein aktiver SMTP-Zugang vorhanden.';
    }
    if ($counts['lists_without_sender'] > 0) {
        $warnings[] = $counts['lists_without_sender'] . ' Liste(n) haben noch keinen aktiven Absender.';
    }
    if ($counts['templates_total'] === 0) {
        $warnings[] = 'Es ist noch keine E-Mail-Vorlage vorhanden.';
    }
    if ($counts['forms_invalid_list'] > 0) {
        $warnings[] = $counts['forms_invalid_list'] . ' Formular(e) verweisen auf keine gueltige Liste.';
    }
    if ($counts['campaigns_invalid_template'] > 0) {
        $warnings[] = $counts['campaigns_invalid_template'] . ' Kampagne(n) haben keine gueltige Vorlage.';
    }
    if ($counts['recipients_total'] > 0 && $counts['lists_total'] === 0) {
        $warnings[] = 'Es gibt bereits Empfaenger, aber noch keine Liste als Versandgrundlage.';
    }

    $definitions = [
        [
            'key' => 'senders',
            'label' => 'Absender anlegen',
            'done' => $counts['active_senders'] > 0,
            'detail_done' => $counts['active_senders'] . ' aktiver Absender vorhanden.',
            'detail_missing' => 'Lege zuerst mindestens einen aktiven Absender an.',
        ],
        [
            'key' => 'smtp',
            'label' => 'SMTP-Zugang anlegen',
            'done' => $counts['active_smtp'] > 0,
            'detail_done' => $counts['active_smtp'] . ' aktiver SMTP-Zugang vorhanden.',
            'detail_missing' => 'Lege mindestens einen aktiven SMTP-Zugang an.',
        ],
        [
            'key' => 'lists',
            'label' => 'Liste anlegen',
            'done' => $counts['lists_total'] > 0,
            'detail_done' => $counts['lists_total'] . ' Liste(n) vorhanden, davon ' . $counts['lists_ready'] . ' mit aktivem Absender.',
            'detail_missing' => 'Lege mindestens eine Liste an und ordne ihr einen Absender zu.',
        ],
        [
            'key' => 'templates',
            'label' => 'Vorlage oder Layout anlegen',
            'done' => $counts['templates_total'] > 0,
            'detail_done' => $counts['templates_total'] . ' Vorlage(n) vorhanden.',
            'detail_missing' => 'Lege mindestens eine E-Mail-Vorlage an.',
        ],
        [
            'key' => 'audience',
            'label' => 'Formular oder Empfaenger anlegen',
            'done' => $counts['forms_total'] > 0 || $counts['recipients_total'] > 0,
            'detail_done' => $counts['forms_total'] . ' Formular(e) und ' . $counts['recipients_total'] . ' Empfaenger vorhanden.',
            'detail_missing' => 'Lege ein Formular oder erste Empfaenger an.',
        ],
        [
            'key' => 'campaigns',
            'label' => 'Kampagne oder Follow-up verwenden',
            'done' => $counts['campaigns_total'] > 0,
            'detail_done' => $counts['campaigns_total'] . ' Kampagne(n) vorhanden, davon ' . $counts['campaigns_scheduled'] . ' geplant.',
            'detail_missing' => 'Lege danach Kampagnen oder Follow-up-Ablaeufe an.',
        ],
    ];

    $steps = [];
    $nextMarked = false;
    foreach ($definitions as $definition) {
        $status = 'done';
        if (!$definition['done']) {
            $status = $nextMarked ? 'missing' : 'next';
            $nextMarked = true;
        }

        $steps[] = [
            'key' => $definition['key'],
            'label' => $definition['label'],
            'status' => $status,
            'detail' => $definition['done'] ? $definition['detail_done'] : $definition['detail_missing'],
        ];
    }

    return [
        'counts' => $counts,
        'warnings' => $warnings,
        'steps' => $steps,
    ];
}

function getSendProtectionStatus(PDO $db, ?array $setup = null): array
{
    $setup = $setup ?? getSystemSetupStatus($db);
    $counts = $setup['counts'];
    $reasons = [];
    $bounceGuardMode = 'normal';
    $bounceGuardSummary = '';

    if (($counts['active_senders'] ?? 0) <= 0) {
        $reasons[] = 'Kein aktiver Absender vorhanden.';
    }
    if (($counts['active_smtp'] ?? 0) <= 0) {
        $reasons[] = 'Kein aktiver SMTP-Zugang vorhanden.';
    }
    if (($counts['lists_total'] ?? 0) <= 0) {
        $reasons[] = 'Keine Liste als Versandgrundlage vorhanden.';
    }
    if (($counts['lists_ready'] ?? 0) <= 0) {
        $reasons[] = 'Keine Liste mit aktivem Absender vorhanden.';
    }
    if (($counts['templates_total'] ?? 0) <= 0) {
        $reasons[] = 'Keine E-Mail-Vorlage vorhanden.';
    }

    try {
        $guardStmt = $db->prepare('SELECT setting_key, setting_value FROM settings WHERE setting_key IN ("bounce_guard_mode", "bounce_guard_summary")');
        $guardStmt->execute();
        $guardSettings = $guardStmt->fetchAll(PDO::FETCH_KEY_PAIR);
        $bounceGuardMode = (string) ($guardSettings['bounce_guard_mode'] ?? 'normal');
        $bounceGuardSummary = (string) ($guardSettings['bounce_guard_summary'] ?? '');
    } catch (Throwable $e) {
        ErrorLogger::logSqlError('Bounce-Guard-Status konnte nicht geladen werden | error: ' . $e->getMessage());
    }

    if ($bounceGuardMode === 'blocked') {
        $reasons[] = $bounceGuardSummary !== '' ? $bounceGuardSummary : 'Bounce-Schutz hat den automatischen Versand blockiert.';
    }

    return [
        'allowed' => $reasons === [],
        'reasons' => $reasons,
        'setup' => $setup,
        'bounce_guard_mode' => $bounceGuardMode,
        'bounce_guard_summary' => $bounceGuardSummary,
    ];
}

function renderSystemStatusPanel(array $setup, array $protection): string
{
    $badgeMap = [
        'done' => ['label' => 'Erledigt', 'class' => 'success'],
        'next' => ['label' => 'Naechster Schritt', 'class' => 'primary'],
        'missing' => ['label' => 'Noch offen', 'class' => 'warning'],
    ];
    $counts = $setup['counts'] ?? [];
    $setupHealthy = empty($setup['warnings']) && !array_filter($setup['steps'], static fn(array $step): bool => $step['status'] !== 'done');
    $setupSummaryBg = $setupHealthy ? '#198754' : '#dc3545';
    $setupSummaryText = $setupHealthy ? '#ffffff' : '#ffffff';
    $protectionSummaryBg = !empty($protection['allowed']) ? '#198754' : '#dc3545';
    $protectionSummaryText = '#ffffff';

    $html = '<div class="row g-4 mb-4">';

    $html .= '<div class="col-12 col-xl-7">';
    $html .= '<div class="card h-100 border-0 shadow-sm">';
    $html .= '<div class="card-body">';
    $html .= '<details style="display:block;border:1px solid #cfd9e3;border-radius:12px;overflow:hidden;background:#fff;">';
    $html .= '<summary style="display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:0.95rem 1.1rem;cursor:pointer;list-style:none;font-weight:700;background:' . $setupSummaryBg . ';color:' . $setupSummaryText . ';">';
    $html .= '<span>Einrichtungsstatus</span>';
    $html .= '<span class="badge" style="background:rgba(255,255,255,0.2);color:#fff;">' . ($setupHealthy ? 'Komplett bereit' : 'Pruefung empfohlen') . '</span>';
    $html .= '</summary>';
    $html .= '<div style="padding:1rem 1.1rem 1.1rem;background:#fff;">';
    $html .= '<p class="text-muted mb-3">Die Reihenfolge dient als Orientierung. Fehlende Punkte werden angezeigt, aber nicht gesperrt.</p>';
    $html .= '<div class="d-flex flex-wrap gap-2 mb-3">';
    $html .= '<span class="badge rounded-pill text-bg-light border">Absender: ' . (int) ($counts['active_senders'] ?? 0) . '</span>';
    $html .= '<span class="badge rounded-pill text-bg-light border">SMTP: ' . (int) ($counts['active_smtp'] ?? 0) . '</span>';
    $html .= '<span class="badge rounded-pill text-bg-light border">Listen: ' . (int) ($counts['lists_total'] ?? 0) . '</span>';
    $html .= '<span class="badge rounded-pill text-bg-light border">Vorlagen: ' . (int) ($counts['templates_total'] ?? 0) . '</span>';
    $html .= '<span class="badge rounded-pill text-bg-light border">Formulare: ' . (int) ($counts['forms_total'] ?? 0) . '</span>';
    $html .= '<span class="badge rounded-pill text-bg-light border">Empfaenger: ' . (int) ($counts['recipients_total'] ?? 0) . '</span>';
    $html .= '</div>';
    $html .= '<div class="list-group list-group-flush">';
    foreach ($setup['steps'] as $index => $step) {
        $badge = $badgeMap[$step['status']] ?? $badgeMap['missing'];
        $itemClass = 'border-start border-4 ps-3';
        if ($step['status'] === 'done') {
            $itemClass .= ' border-success';
        } elseif ($step['status'] === 'next') {
            $itemClass .= ' border-primary';
        } else {
            $itemClass .= ' border-warning';
        }
        $html .= '<div class="list-group-item px-0 py-3 ' . $itemClass . '">';
        $html .= '<div class="d-flex justify-content-between align-items-start gap-3 flex-wrap">';
        $html .= '<div class="me-auto"><div class="fw-semibold">' . ($index + 1) . '. ' . htmlspecialchars($step['label'], ENT_QUOTES, 'UTF-8') . '</div>';
        $html .= '<div class="text-muted small mt-1">' . htmlspecialchars($step['detail'], ENT_QUOTES, 'UTF-8') . '</div></div>';
        $html .= '<span class="badge text-bg-' . $badge['class'] . ' mt-1">' . htmlspecialchars($badge['label'], ENT_QUOTES, 'UTF-8') . '</span>';
        $html .= '</div>';
        $html .= '</div>';
    }
    $html .= '</div>';
    if (!empty($setup['warnings'])) {
        $html .= '<div class="alert alert-warning mt-3 mb-0">';
        $html .= '<div class="fw-semibold mb-2">Hinweise zur Einrichtung</div><ul class="mb-0 ps-3 small">';
        foreach ($setup['warnings'] as $warning) {
            $html .= '<li>' . htmlspecialchars($warning, ENT_QUOTES, 'UTF-8') . '</li>';
        }
        $html .= '</ul></div>';
    }
    $html .= '</div>';
    $html .= '</details>';
    $html .= '</div></div></div>';

    $statusClass = !empty($protection['allowed']) ? 'success' : 'danger';
    $statusText = !empty($protection['allowed']) ? 'Automatischer Versand freigegeben' : 'Automatischer Versand blockiert';

    $html .= '<div class="col-12 col-xl-5">';
    $html .= '<div class="card h-100 border-0 shadow-sm">';
    $html .= '<div class="card-body">';
    $html .= '<details style="display:block;border:1px solid #cfd9e3;border-radius:12px;overflow:hidden;background:#fff;">';
    $html .= '<summary style="display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:0.95rem 1.1rem;cursor:pointer;list-style:none;font-weight:700;background:' . $protectionSummaryBg . ';color:' . $protectionSummaryText . ';">';
    $html .= '<span>Versandschutz</span>';
    $html .= '<span class="badge" style="background:rgba(255,255,255,0.2);color:#fff;">' . (!empty($protection['allowed']) ? 'Freigegeben' : 'Blockiert') . '</span>';
    $html .= '</summary>';
    $html .= '<div style="padding:1rem 1.1rem 1.1rem;background:#fff;">';
    $html .= '<div class="alert alert-' . $statusClass . ' mb-3"><strong>' . htmlspecialchars($statusText, ENT_QUOTES, 'UTF-8') . '</strong><div class="small mt-1">Der Schutz greift nur fuer den automatischen Versand.</div></div>';
    $html .= '<p class="text-muted mb-3">Pflege, Einrichtung und manuelle Arbeiten bleiben weiterhin moeglich.</p>';
    if (!empty($protection['allowed'])) {
        $html .= '<div class="fw-semibold mb-2">Gepruefte Voraussetzungen</div>';
        $html .= '<ul class="mb-0 ps-3 small">';
        $html .= '<li>Mindestens ein aktiver Absender ist vorhanden.</li>';
        $html .= '<li>Mindestens ein aktiver SMTP-Zugang ist vorhanden.</li>';
        $html .= '<li>Es gibt mindestens eine Liste mit aktivem Absender.</li>';
        $html .= '<li>Es ist mindestens eine E-Mail-Vorlage vorhanden.</li>';
        $html .= '</ul>';
    } else {
        $html .= '<div class="fw-semibold mb-2">Aktuelle Blockierungsgruende</div><ul class="mb-0 ps-3 small">';
        foreach ($protection['reasons'] as $reason) {
            $html .= '<li>' . htmlspecialchars($reason, ENT_QUOTES, 'UTF-8') . '</li>';
        }
        $html .= '</ul>';
        $html .= '<div class="small text-muted mt-3">Sobald diese Kernvoraussetzungen erfuellt sind, kann der automatische Versand wieder laufen.</div>';
    }
    $html .= '</div>';
    $html .= '</details>';
    $html .= '</div></div></div>';

    $html .= '</div>';

    return $html;
}

/**
 * Helper: Tag-ID anhand Name holen (z. B. "inaktiv")
 * ----------------------------------------------------------------------
 * ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€šÃ‚Â¢ Cacht pro Request (static), damit keine unnÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¶tigen DB-Queries entstehen
 * ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€šÃ‚Â¢ Logging bei Erfolg/Fehler
 */
function getTagIdByName(PDO $db, string $tagName): ?int
{
    static $cache = [];

    $key = mb_strtolower(trim($tagName));
    if ($key === '') {
        return null;
    }

    // Cache-Hit -> keine DB-Query nÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¶tig
    if (array_key_exists($key, $cache)) {
        return $cache[$key];
    }

    try {
        $sql = "SELECT id FROM tags WHERE name = ? LIMIT 1";
        $stmt = $db->prepare($sql);
        $stmt->execute([$tagName]);
        $id = $stmt->fetchColumn();

        ErrorLogger::logSqlSuccess(__FILE__ . ' | SELECT tags.id by name=' . $tagName);

        $cache[$key] = $id ? (int)$id : null;
        return $cache[$key];
    } catch (Throwable $e) {
        ErrorLogger::logSqlError(__FILE__ . ' | getTagIdByName(' . $tagName . '): ' . $e->getMessage());
        $cache[$key] = null;
        return null;
    }
}

/**
 * Helper: "inaktiv"-Tag fÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼r einen EmpfÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¤nger entfernen (wenn vorhanden)
 * ----------------------------------------------------------------------
 * ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€šÃ‚Â¢ Entfernt nur die Zuordnung in recipient_tags (nicht den Tag selbst!)
 * ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€šÃ‚Â¢ Logging bei Erfolg/Fehler
 * ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€šÃ‚Â¢ Gibt Anzahl gelÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¶schter Zuordnungen zurÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼ck (0/1)
 */
function removeInactiveTagIfExists(PDO $db, int $recipientId, string $tagName = 'inaktiv'): int
{
    if ($recipientId <= 0) {
        return 0;
    }

    $tagId = getTagIdByName($db, $tagName);
    if (!$tagId) {
        // Tag existiert nicht -> nichts zu tun
        return 0;
    }

    try {
        $sql = "DELETE FROM recipient_tags WHERE recipient_id = ? AND tag_id = ?";
        $stmt = $db->prepare($sql);
        $stmt->execute([$recipientId, $tagId]);

        $deleted = (int)$stmt->rowCount();
        ErrorLogger::logSqlSuccess(
            __FILE__,
            "DELETE recipient_tags recipient_id={$recipientId} tag_id={$tagId} (tag='{$tagName}') deleted={$deleted}"
        );

        return $deleted;
    } catch (Throwable $e) {
        // Wichtig: Tracking darf nicht sterben
        ErrorLogger::logSqlError(__FILE__ . ' | removeInactiveTagIfExists(' . $recipientId . '): ' . $e->getMessage());
        return 0;
    }
}


/**
 * PrÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼ft, ob eine E-Mail-Adresse durch die Sperrliste blockiert ist.
 * Diese Funktion wird bewusst nur an den Stellen verwendet, wo Adressen "reinkommen"
 * (registrieren.php + Import), nicht beim Versand/Queueing.
 *
 * RÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼ckgabe:
 * - false => NICHT gesperrt (Adresse darf angelegt/importiert werden)
 * - array => GESPERRT (Details zu Typ/Grund)
 *
 * Logging:
 * - Jede SQL-Operation wird via ErrorLogger::logSqlSuccess / logSqlError protokolliert.
 */
function isEmailSuppressed(PDO $db, string $email)
{
    // ------------------------------
    // 1) Normalisierung & Grundvalidierung
    // ------------------------------
    $email = trim(strtolower($email));

    // Wenn "kaputte" Eingabe kommt, behandeln wir sie als "nicht sperren"
    // (Validierung/Reject passiert idealerweise schon vorher im Formular/Import).
    if ($email === '' || strpos($email, '@') === false) {
        return false;
    }

    // Domain extrahieren (fÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼r Domain-Sperren)
    $domain = substr(strrchr($email, "@"), 1);
    $domain = trim(strtolower($domain));

    try {
        // ------------------------------
        // 2) SQL: PrÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼fen, ob E-Mail ODER Domain in Sperrliste aktiv ist
        //    + optionales Ablaufdatum berÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼cksichtigen
        // ------------------------------
        $sql = "
            SELECT id, type, value, reason, details, expires_at
            FROM suppression_list
            WHERE is_active = 1
              AND (expires_at IS NULL OR expires_at > NOW())
              AND (
                   (type = 'email'  AND value = :email)
                OR (type = 'domain' AND value = :domain)
              )
            ORDER BY
              -- E-Mail ist spezifischer als Domain => bevorzugt
              CASE WHEN type = 'email' THEN 0 ELSE 1 END
            LIMIT 1
        ";

        $stmt = $db->prepare($sql);
        $stmt->execute([
            ':email'  => $email,
            ':domain' => $domain
        ]);

        $hit = $stmt->fetch(PDO::FETCH_ASSOC);

        ErrorLogger::logSqlSuccess('Sperrliste Check (intake) | context: ' . json_encode(['email' => $email, 'domain' => $domain, 'blocked' => (bool)$hit], JSON_UNESCAPED_UNICODE));

        // Treffer => gesperrt
        if ($hit) {
            return $hit;
        }

        // Kein Treffer => nicht gesperrt
        return false;

    } catch (Exception $e) {
        // Wenn die SperrlistenprÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¼fung ausfÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¤llt, loggen wir das.
        // Ob du in dem Fall "fail-open" (zulassen) oder "fail-closed" (blocken) willst:
        // Du wolltest minimal invasiv -> fail-open (zulassen), damit nichts kaputt geht.
        ErrorLogger::logSqlError('Sperrliste Check (intake) fehlgeschlagen | error: ' . $e->getMessage());
        return false;
    }
}

function isMemberModuleEnabled(?array $config = null): bool
{
    $config = $config ?? (include __DIR__ . '/config.php');
    return !empty($config['member']['enabled']);
}

function projectBasePath(array $config): string
{
    $baseUrl = trim((string) ($config['app']['base_url'] ?? ''));
    $path = (string) parse_url($baseUrl, PHP_URL_PATH);
    $path = trim($path, '/');
    return $path === '' ? '' : '/' . $path;
}

function memberBasePath(?array $config = null): string
{
    $config = $config ?? (include __DIR__ . '/config.php');
    return projectBasePath($config) . '/member';
}

function memberUrl(string $path = '', ?array $config = null): string
{
    $config = $config ?? (include __DIR__ . '/config.php');
    $baseUrl = rtrim((string) ($config['app']['base_url'] ?? ''), '/');
    $path = ltrim($path, '/');
    return $baseUrl . '/member' . ($path !== '' ? '/' . $path : '');
}

function mrWrapEmailShell(string $html, int $contentWidth = 700, string $outerBackground = '#EEF2F7', string $innerBackground = '#FFFFFF'): string
{
    $contentWidth = max(480, min(900, $contentWidth));
    return '<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head><body style="margin:0;padding:0;background:' . htmlspecialchars($outerBackground, ENT_QUOTES, 'UTF-8') . ';"><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="border-collapse:collapse;background:' . htmlspecialchars($outerBackground, ENT_QUOTES, 'UTF-8') . ';"><tr><td align="center" style="padding:24px 12px;"><table role="presentation" width="' . $contentWidth . '" cellpadding="0" cellspacing="0" border="0" style="border-collapse:collapse;width:100%;max-width:' . $contentWidth . 'px;background:' . htmlspecialchars($innerBackground, ENT_QUOTES, 'UTF-8') . ';"><tr><td style="padding:0;">' . $html . '</td></tr></table></td></tr></table></body></html>';
}
