<?php
/**
 * click.php – Tracking für Link-Klicks inkl. Öffnungs-Fallback
 * ----------------------------------------------------------------------
 * Setting A:
 *  • suspicious_score >= 5 => suspected (Scanner)
 *  • suspected Klicks:
 *      - werden geloggt
 *      - leiten weiter
 *      - setzen KEIN last_clicked_at
 *      - erzeugen KEIN Open-via-click
 *      - entfernen KEIN "inaktiv"-Tag
 */

require_once __DIR__ . '/includes/init.php';
require_once __DIR__ . '/includes/core/ErrorLogger.php';



/* =========================================================================
 * KONFIGURATION
 * ========================================================================= */
const SUSPICIOUS_MIN_SCORE = 5; // Setting A

function resolveTagIdByName(PDO $db, string $tagName): int
{
    $tagName = trim($tagName);
    if ($tagName === '') {
        return 0;
    }

    try {
        $stmt = $db->prepare("SELECT id FROM tags WHERE name = ? LIMIT 1");
        $stmt->execute([$tagName]);
        ErrorLogger::logSqlSuccess('click: load tag id | SQL: ' . $stmt->queryString . ' | params: ' . json_encode([$tagName], JSON_UNESCAPED_UNICODE));

        return (int)($stmt->fetchColumn() ?: 0);
    } catch (Throwable $e) {
        ErrorLogger::logSqlError('click: resolve tag failed | error: ' . $e->getMessage());
        return 0;
    }
}

function loadLinkActions(PDO $db, int $trackingId): array
{
    if ($trackingId <= 0) {
        return [];
    }

    try {
        $stmt = $db->prepare(
            "SELECT id, action_type, tag_id, only_once, executed_at
               FROM email_link_actions
              WHERE email_link_tracking_id = ?"
        );
        $stmt->execute([$trackingId]);
        ErrorLogger::logSqlSuccess('click: load link actions | SQL: ' . $stmt->queryString . ' | params: ' . json_encode([$trackingId], JSON_UNESCAPED_UNICODE));

        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    } catch (Throwable $e) {
        ErrorLogger::logSqlError('click: load link actions failed | error: ' . $e->getMessage());
        return [];
    }
}

function markLinkActionExecuted(PDO $db, int $actionId): void
{
    if ($actionId <= 0) {
        return;
    }

    try {
        $stmt = $db->prepare('UPDATE email_link_actions SET executed_at = NOW() WHERE id = ? AND executed_at IS NULL');
        $stmt->execute([$actionId]);
        ErrorLogger::logSqlSuccess('click: mark link action executed | SQL: ' . $stmt->queryString . ' | params: ' . json_encode([$actionId], JSON_UNESCAPED_UNICODE));
    } catch (Throwable $e) {
        ErrorLogger::logSqlError('click: mark link action executed failed | error: ' . $e->getMessage());
    }
}

function applyLinkActions(PDO $db, RecipientAutomationService $service, array $actions, int $recipientId): void
{
    foreach ($actions as $action) {
        $actionType = (string)($action['action_type'] ?? '');
        $actionId = (int)($action['id'] ?? 0);
        $tagId = (int)($action['tag_id'] ?? 0);
        $onlyOnce = !empty($action['only_once']);

        if ($tagId <= 0) {
            continue;
        }

        if ($onlyOnce && !empty($action['executed_at'])) {
            ErrorLogger::logSqlSuccess('click: skip link action due to only_once | context: ' . json_encode(['recipient_id' => $recipientId, 'tag_id' => $tagId, 'action_type' => $actionType], JSON_UNESCAPED_UNICODE));
            continue;
        }

        if ($actionType === 'assign_tag') {
            $service->assignTagToRecipient($recipientId, $tagId, [
                'source' => 'link_click',
                'source_action_id' => $actionId,
            ]);
            if ($onlyOnce) {
                markLinkActionExecuted($db, $actionId);
            }
            continue;
        }

        if ($actionType === 'remove_tag') {
            $service->removeTagFromRecipient($recipientId, $tagId, [
                'source' => 'link_click',
                'source_action_id' => $actionId,
            ]);
            if ($onlyOnce) {
                markLinkActionExecuted($db, $actionId);
            }
        }
    }
}

/**
 * Prüft, ob aktueller Klick suspected ist
 */
function detectSuspiciousClick(PDO $db, string $ip): bool
{
    if (trim($ip) === '' || $ip === 'unknown') {
        return false;
    }

    try {
        $stmt = $db->prepare(
            "SELECT 1
               FROM suspicious_ips
              WHERE ip_address = (CONVERT(? USING utf8mb4) COLLATE utf8mb4_unicode_ci)
                AND NOW() BETWEEN window_start AND window_end
                AND suspicion_score >= ?
              LIMIT 1"
        );

        $stmt->execute([$ip, SUSPICIOUS_MIN_SCORE]);
        ErrorLogger::logSqlSuccess('click: suspicious ip check | SQL: ' . $stmt->queryString . ' | params: ' . json_encode([$ip, SUSPICIOUS_MIN_SCORE], JSON_UNESCAPED_UNICODE));

        return (bool)$stmt->fetchColumn();

    } catch (Throwable $e) {
        ErrorLogger::logSqlError('click: suspicious check failed (fail-safe) | error: ' . $e->getMessage());
        return false;
    }
}

try {

    /* -----------------------------------------------------------------
     * 0) DB & Transaktion
     * ----------------------------------------------------------------- */
    $db = Database::getInstance();
    $db->beginTransaction();

    /* -----------------------------------------------------------------
     * 1) Token prüfen
     * ----------------------------------------------------------------- */
    $token = $_GET['token'] ?? '';
    if (empty($token)) {
        http_response_code(400);
        exit('Token fehlt.');
    }

    $stmt = $db->prepare(
        "SELECT id, original_url, queue_id, clicked_at
           FROM email_link_tracking
          WHERE token = ?"
    );
    $stmt->execute([$token]);
    ErrorLogger::logSqlSuccess('click: load link by token | SQL: ' . $stmt->queryString . ' | params: ' . json_encode([$token], JSON_UNESCAPED_UNICODE));

    $link = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$link) {
        ErrorLogger::logSqlError('click: invalid link token');
        http_response_code(404);
        exit('Ungültiger Link.');
    }

    /* -----------------------------------------------------------------
     * 2) Empfänger ermitteln
     * ----------------------------------------------------------------- */
    $stmt = $db->prepare(
        "SELECT recipient_id
           FROM send_queue
          WHERE id = ?"
    );
    $stmt->execute([$link['queue_id']]);
    ErrorLogger::logSqlSuccess('click: load queue entry | SQL: ' . $stmt->queryString . ' | params: ' . json_encode([$link['queue_id']], JSON_UNESCAPED_UNICODE));

    $queue = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$queue) {
        http_response_code(404);
        exit('Queue-Eintrag nicht gefunden.');
    }

    $recipientId = (int)$queue['recipient_id'];
    $linkActions = loadLinkActions($db, (int)$link['id']);
    $recipientAutomationService = new RecipientAutomationService($db);
    new AutomationRuleEngine($db, $recipientAutomationService);

    /* -----------------------------------------------------------------
     * 3) Meta-Daten erfassen
     * ----------------------------------------------------------------- */
    $ip        = $_SERVER['REMOTE_ADDR']     ?? 'unknown';
    $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
    $device    = 'unknown';

    if (preg_match('/mobile|android|touch|webos|hpwos/i', $userAgent)) {
        $device = 'mobile';
    } elseif (preg_match('/windows|macintosh|linux/i', $userAgent)) {
        $device = 'desktop';
    }

    /* -----------------------------------------------------------------
     * 4) Suspicious prüfen (Setting A)
     * ----------------------------------------------------------------- */
    $isSuspected = detectSuspiciousClick($db, $ip);

    /* -----------------------------------------------------------------
     * 5) Klick immer loggen
     * ----------------------------------------------------------------- */
    $stmt = $db->prepare(
        "UPDATE email_link_tracking
            SET clicked_at  = NOW(),
                ip_address  = ?,
                user_agent  = ?,
                device_type = ?
          WHERE token = ?"
    );
    $stmt->execute([$ip, $userAgent, $device, $token]);
    ErrorLogger::logSqlSuccess('click: update link click | SQL: ' . $stmt->queryString . ' | params: ' . json_encode([$ip, $userAgent, $device, $token], JSON_UNESCAPED_UNICODE));

    /* -----------------------------------------------------------------
     * 6) Nur echte Klicks beeinflussen Engagement
     * ----------------------------------------------------------------- */
    if (!$isSuspected) {


        // Open nachtragen falls noch nicht vorhanden
        $stmt = $db->prepare(
            "SELECT 1 FROM email_opens WHERE queue_id = ? LIMIT 1"
        );
        $stmt->execute([(int)$link['queue_id']]);

        if (!$stmt->fetchColumn()) {

            $stmt = $db->prepare(
                "INSERT INTO email_opens
                    (queue_id, opened_at, ip_address, user_agent, device_type)
                 VALUES (?, NOW(), ?, ?, ?)"
            );
            $stmt->execute([(int)$link['queue_id'], $ip, $userAgent, $device]);

            $stmt = $db->prepare(
                "UPDATE recipients SET last_opened_at = NOW() WHERE id = ?"
            );
            $stmt->execute([$recipientId]);
        }

        // last_clicked_at setzen
        $stmt = $db->prepare(
            "UPDATE recipients
                SET last_clicked_at = NOW()
              WHERE id = ?"
        );
        $stmt->execute([$recipientId]);

        // Tag "inaktiv" entfernen
        $inactiveTagId = resolveTagIdByName($db, 'inaktiv');
        if ($inactiveTagId > 0) {
            $recipientAutomationService->removeTagFromRecipient($recipientId, $inactiveTagId, [
                'source' => 'link_click',
                'source_action' => 'remove_inactive',
            ]);
        }

        // Optionale Link-Aktionen verarbeiten
        applyLinkActions($db, $recipientAutomationService, $linkActions, $recipientId);

    } else {

        // Optionales Log
        ErrorLogger::logSqlSuccess('click: suspected click ignored for engagement | context: ' . json_encode(['ip' => $ip], JSON_UNESCAPED_UNICODE));
    }

    /* -----------------------------------------------------------------
     * 7) Commit
     * ----------------------------------------------------------------- */
    $db->commit();

} catch (Throwable $e) {

    if (isset($db) && $db->inTransaction()) {
        $db->rollBack();
    }

    ErrorLogger::logSqlError('click: workflow failed | error: ' . $e->getMessage());
    http_response_code(500);
    exit('Interner Fehler.');
}

/* ---------------------------------------------------------------------
 * 8) Weiterleitung
 * ------------------------------------------------------------------- */
header('Location: ' . $link['original_url']);
exit;




