<?php
/**
 * admin/tools/suspicious_ips.php
 * -----------------------------------------------------------------------------
 * ✅ MR9 Admin-Tool: Verdächtige IPs (Analyse) anzeigen + Filter (erweiterbar)
 *
 * Datenquelle:
 *  • suspicious_ips (Analyse-Tabelle aus dem Cron)
 *
 * Erweiterung:
 *  • Score-Stufen werden jetzt zusätzlich als "Einordnung" angezeigt:
 *      - Score 0     => —
 *      - Score 1–2   => Normal
 *      - Score 3–4   => Verdächtig
 *      - Score >=5   => Scanner (Fake)
 *
 * Anforderungen (MR9-Style):
 *  • Auth Pflicht
 *  • try/catch Fehlerbehandlung
 *  • SQL Logging: ErrorLogger::logSqlSuccess / logSqlError
 *  • Strukturierte Anzeige + "TML-Icons"
 *  • Auto-Dismiss Hinweise
 */

session_start();
require_once __DIR__ . '/../../includes/init.php';
require_once __DIR__ . '/../../auth/AuthController.php';

$auth = new AuthController();
if (!$auth->isLoggedIn()) {
    header('Location: ' . $adminLoginPath);
    exit;
}

$db = Database::getInstance();

/* =========================================================================
 * Helper: TML Icon
 * ========================================================================= */
function tmlIcon(string $name, string $extraClass = ''): string
{
    $name = preg_replace('/[^a-z0-9\-_]/i', '', $name);
    $extraClass = trim($extraClass);
    return '<i class="tml-icon tml-icon-' . htmlspecialchars($name) . ' ' . htmlspecialchars($extraClass) . '"></i>';
}

/* =========================================================================
 * Helper: Score Einordnung
 * ========================================================================= */
function scoreLabel(int $score): string
{
    if ($score >= 5) return 'Scanner (Fake)';
    if ($score >= 3) return 'Verdächtig';
    if ($score >= 1) return 'Normal';
    return '—';
}

function scoreBadgeClass(int $score): string
{
    if ($score >= 5) return 'bg-danger';
    if ($score >= 3) return 'bg-warning text-dark';
    if ($score >= 1) return 'bg-info text-dark';
    return 'bg-secondary';
}

/* =========================================================================
 * 1) Filter aus GET lesen
 * ========================================================================= */
$ip        = trim((string)($_GET['ip'] ?? ''));
$minScore  = (int)($_GET['min_score'] ?? 0);
$fromDate  = trim((string)($_GET['from'] ?? '')); // YYYY-MM-DD
$toDate    = trim((string)($_GET['to'] ?? ''));   // YYYY-MM-DD
$sort      = trim((string)($_GET['sort'] ?? 'newest'));
$page      = max(1, (int)($_GET['page'] ?? 1));
$perPage   = 50;

$allowedSort = [
    'newest'      => 'window_end DESC, id DESC',
    'score_desc'  => 'suspicion_score DESC, window_end DESC',
    'clicks_desc' => 'clicks_total DESC, window_end DESC',
    'burst_desc'  => 'max_clicks_per_minute DESC, window_end DESC',
];
$orderBySql = $allowedSort[$sort] ?? $allowedSort['newest'];

/* =========================================================================
 * Datum validieren (robust)
 * ========================================================================= */
$fromDateTime = null;
$toDateTime   = null;

if ($fromDate !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $fromDate)) {
    $fromDateTime = $fromDate . ' 00:00:00';
}
if ($toDate !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $toDate)) {
    $toDateTime = $toDate . ' 23:59:59';
}

/* =========================================================================
 * 2) SQL zusammenbauen (prepared + Whitelist-Order)
 * ========================================================================= */
$where = [];
$params = [];

if ($ip !== '') {
    $where[] = 'ip_address LIKE :ip';
    $params[':ip'] = '%' . $ip . '%';
}
if ($minScore > 0) {
    $where[] = 'suspicion_score >= :min_score';
    $params[':min_score'] = $minScore;
}
if ($fromDateTime !== null) {
    $where[] = 'window_end >= :from_dt';
    $params[':from_dt'] = $fromDateTime;
}
if ($toDateTime !== null) {
    $where[] = 'window_end <= :to_dt';
    $params[':to_dt'] = $toDateTime;
}

$whereSql = $where ? ('WHERE ' . implode(' AND ', $where)) : '';

$offset = ($page - 1) * $perPage;

$items = [];
$totalRows = 0;
$notice = null;
$error  = null;

try {
    /* -------------------------------------------------------------------------
     * 2a) Count für Pagination
     * ---------------------------------------------------------------------- */
    $sqlCount = "SELECT COUNT(*) FROM suspicious_ips {$whereSql}";
    try {
        $stmt = $db->prepare($sqlCount);
        $stmt->execute($params);
        $totalRows = (int)$stmt->fetchColumn();

        ErrorLogger::logSqlSuccess('suspicious_ips count | SQL: ' . $sqlCount . ' | context: ' . json_encode(['params' => $params, 'totalRows' => $totalRows], JSON_UNESCAPED_UNICODE));
    } catch (Throwable $e) {
        ErrorLogger::logSqlError('suspicious_ips count | SQL: ' . $sqlCount . ' | context: ' . json_encode(['params' => $params], JSON_UNESCAPED_UNICODE) . ' | error: ' . $e->getMessage());
        throw $e;
    }

    /* -------------------------------------------------------------------------
     * 2b) Daten laden (LIMIT/OFFSET als INT binden)
     * ---------------------------------------------------------------------- */
    $sqlList = "
        SELECT
            id,
            ip_address,
            window_start,
            window_end,
            clicks_total,
            uniq_queue_click,
            max_clicks_per_minute,
            opens_total,
            uniq_queue_open,
            suspicion_score,
            reasons,
            created_at
        FROM suspicious_ips
        {$whereSql}
        ORDER BY {$orderBySql}
        LIMIT :limit OFFSET :offset
    ";

    try {
        $stmt = $db->prepare($sqlList);

        foreach ($params as $k => $v) {
            $stmt->bindValue($k, $v);
        }

        $stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);
        $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);

        $stmt->execute();
        $items = $stmt->fetchAll(PDO::FETCH_ASSOC);

        ErrorLogger::logSqlSuccess('suspicious_ips list | SQL: ' . $sqlList . ' | context: ' . json_encode(['params' => $params, 'limit' => $perPage, 'offset' => $offset, 'rows' => count($items), 'order' => $orderBySql], JSON_UNESCAPED_UNICODE));
    } catch (Throwable $e) {
        ErrorLogger::logSqlError('suspicious_ips list | SQL: ' . $sqlList . ' | context: ' . json_encode(['params' => $params, 'limit' => $perPage, 'offset' => $offset, 'order' => $orderBySql], JSON_UNESCAPED_UNICODE) . ' | error: ' . $e->getMessage());
        throw $e;
    }

    $notice = "Anzeige: " . count($items) . " von " . $totalRows . " Einträgen.";

} catch (Throwable $e) {
    $error = "Fehler beim Laden der Verdachts-IP-Liste: " . $e->getMessage();
}

/* =========================================================================
 * 3) Rendering via Template
 * ========================================================================= */
ob_start();
?>
<div class="container-fluid">
    <div class="d-flex align-items-center justify-content-between mb-3">
        <h3 class="mb-0">
            <?= tmlIcon('shield', 'me-2'); ?>
            Verdächtige IPs (Analyse)
        </h3>

        <div class="text-muted small">
            <?= tmlIcon('clock', 'me-1'); ?>
            Zeitraum: <?= htmlspecialchars($fromDateTime ?? '—'); ?> bis <?= htmlspecialchars($toDateTime ?? '—'); ?>
        </div>
    </div>

    <?php if ($notice): ?>
        <div class="alert alert-info d-flex align-items-center gap-2 auto-dismiss" role="alert">
            <?= tmlIcon('info', ''); ?>
            <div><?= htmlspecialchars($notice); ?></div>
        </div>
    <?php endif; ?>

    <?php if ($error): ?>
        <div class="alert alert-danger d-flex align-items-center gap-2 auto-dismiss" role="alert">
            <?= tmlIcon('alert', ''); ?>
            <div><?= htmlspecialchars($error); ?></div>
        </div>
    <?php endif; ?>

    <!-- Einordnung / Legende -->
    <div class="alert alert-secondary d-flex align-items-center gap-2 auto-dismiss" role="alert">
        <?= tmlIcon('info', ''); ?>
        <div class="small">
            <strong>Score Einordnung:</strong>
            <span class="badge bg-secondary ms-2">0</span> — (keine Auffälligkeit) ·
            <span class="badge bg-info text-dark ms-2">1–2</span> Normal ·
            <span class="badge bg-warning text-dark ms-2">3–4</span> Verdächtig ·
            <span class="badge bg-danger ms-2">≥5</span> Scanner (Fake)
        </div>
    </div>

    <!-- Filterbox -->
    <div class="card mb-3">
        <div class="card-body">
            <form method="get" class="row g-2 align-items-end">
                <div class="col-12 col-md-3">
                    <label class="form-label mb-1">IP enthält</label>
                    <input type="text" name="ip" class="form-control" value="<?= htmlspecialchars($ip); ?>" placeholder="z.B. 185.">
                </div>

                <div class="col-6 col-md-2">
                    <label class="form-label mb-1">Min. Score</label>
                    <input type="number" name="min_score" class="form-control" value="<?= (int)$minScore; ?>" min="0" step="1">
                </div>

                <div class="col-6 col-md-2">
                    <label class="form-label mb-1">Von (YYYY-MM-DD)</label>
                    <input type="text" name="from" class="form-control" value="<?= htmlspecialchars($fromDate); ?>" placeholder="2026-03-01">
                </div>

                <div class="col-6 col-md-2">
                    <label class="form-label mb-1">Bis (YYYY-MM-DD)</label>
                    <input type="text" name="to" class="form-control" value="<?= htmlspecialchars($toDate); ?>" placeholder="2026-03-01">
                </div>

                <div class="col-6 col-md-2">
                    <label class="form-label mb-1">Sortierung</label>
                    <select name="sort" class="form-select">
                        <option value="newest" <?= $sort === 'newest' ? 'selected' : ''; ?>>Neueste zuerst</option>
                        <option value="score_desc" <?= $sort === 'score_desc' ? 'selected' : ''; ?>>Score (absteigend)</option>
                        <option value="clicks_desc" <?= $sort === 'clicks_desc' ? 'selected' : ''; ?>>Klicks (absteigend)</option>
                        <option value="burst_desc" <?= $sort === 'burst_desc' ? 'selected' : ''; ?>>Burst/min (absteigend)</option>
                    </select>
                </div>

                <div class="col-12 col-md-1 d-grid">
                    <button class="btn btn-primary" type="submit">
                        <?= tmlIcon('filter', 'me-1'); ?> Filtern
                    </button>
                </div>

                <div class="col-12 col-md-2 d-grid">
                    <a class="btn btn-outline-secondary" href="suspicious_ips.php">
                        <?= tmlIcon('refresh', 'me-1'); ?> Reset
                    </a>
                </div>
            </form>

            <div class="text-muted small mt-2">
                <?= tmlIcon('info', 'me-1'); ?>
                Hinweis: Diese Seite ist <strong>Analyse-only</strong>. Das Blocking passiert erst in <code>click.php</code>/<code>open.php</code>
                über <code>score &gt;= 5</code>.
            </div>
        </div>
    </div>

    <!-- Ergebnisliste -->
    <div class="card">
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-striped table-hover mb-0 align-middle">
                    <thead class="table-light">
                        <tr>
                            <th style="width: 70px;">ID</th>
                            <th>IP</th>
                            <th>Fenster</th>
                            <th class="text-end">Score</th>
                            <th>Einordnung</th>
                            <th class="text-end">Klicks</th>
                            <th class="text-end">uniq queue (Klick)</th>
                            <th class="text-end">max/min</th>
                            <th class="text-end">Opens</th>
                            <th class="text-end">uniq queue (Open)</th>
                            <th>Gründe</th>
                            <th style="width: 160px;">Erfasst</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php if (!$items): ?>
                            <tr>
                                <td colspan="12" class="text-center text-muted p-4">
                                    <?= tmlIcon('empty', 'me-1'); ?>
                                    Keine Einträge gefunden (Filter ggf. zurücksetzen).
                                </td>
                            </tr>
                        <?php else: ?>
                            <?php foreach ($items as $r): ?>
                                <?php
                                    $score = (int)$r['suspicion_score'];
                                    $badgeClass = scoreBadgeClass($score);
                                    $label = scoreLabel($score);

                                    $window = htmlspecialchars((string)$r['window_start']) . " → " . htmlspecialchars((string)$r['window_end']);
                                ?>
                                <tr>
                                    <td><?= (int)$r['id']; ?></td>
                                    <td>
                                        <?= tmlIcon('network', 'me-1'); ?>
                                        <code><?= htmlspecialchars((string)$r['ip_address']); ?></code>
                                    </td>

                                    <td class="small text-muted"><?= $window; ?></td>

                                    <td class="text-end">
                                        <span class="badge <?= $badgeClass; ?>">
                                            <?= $score; ?>
                                        </span>
                                    </td>

                                    <td class="small">
                                        <?php if ($score >= 5): ?>
                                            <span class="badge bg-danger"><?= htmlspecialchars($label); ?></span>
                                        <?php elseif ($score >= 3): ?>
                                            <span class="badge bg-warning text-dark"><?= htmlspecialchars($label); ?></span>
                                        <?php elseif ($score >= 1): ?>
                                            <span class="badge bg-info text-dark"><?= htmlspecialchars($label); ?></span>
                                        <?php else: ?>
                                            <span class="badge bg-secondary"><?= htmlspecialchars($label); ?></span>
                                        <?php endif; ?>
                                    </td>

                                    <td class="text-end"><?= (int)$r['clicks_total']; ?></td>
                                    <td class="text-end"><?= (int)$r['uniq_queue_click']; ?></td>
                                    <td class="text-end"><?= (int)$r['max_clicks_per_minute']; ?></td>

                                    <td class="text-end"><?= (int)$r['opens_total']; ?></td>
                                    <td class="text-end"><?= (int)$r['uniq_queue_open']; ?></td>

                                    <td class="small">
                                        <?= htmlspecialchars((string)($r['reasons'] ?? '')); ?>
                                    </td>

                                    <td class="small text-muted">
                                        <?= htmlspecialchars((string)$r['created_at']); ?>
                                    </td>
                                </tr>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </tbody>
                </table>
            </div>
        </div>

        <!-- Pagination -->
        <?php
            $totalPages = (int)ceil($totalRows / $perPage);
            $baseParams = $_GET;
        ?>
        <?php if ($totalPages > 1): ?>
            <div class="card-footer d-flex align-items-center justify-content-between">
                <div class="text-muted small">
                    Seite <?= $page; ?> / <?= $totalPages; ?> (<?= $totalRows; ?> Einträge)
                </div>

                <nav aria-label="Pagination">
                    <ul class="pagination mb-0">
                        <?php
                            $prev = max(1, $page - 1);
                            $next = min($totalPages, $page + 1);

                            $baseParams['page'] = $prev;
                            $prevUrl = 'suspicious_ips.php?' . http_build_query($baseParams);

                            $baseParams['page'] = $next;
                            $nextUrl = 'suspicious_ips.php?' . http_build_query($baseParams);

                            $disabledPrev = $page <= 1 ? 'disabled' : '';
                            $disabledNext = $page >= $totalPages ? 'disabled' : '';
                        ?>
                        <li class="page-item <?= $disabledPrev; ?>">
                            <a class="page-link" href="<?= $disabledPrev ? '#' : htmlspecialchars($prevUrl); ?>">«</a>
                        </li>
                        <li class="page-item disabled">
                            <span class="page-link"><?= $page; ?></span>
                        </li>
                        <li class="page-item <?= $disabledNext; ?>">
                            <a class="page-link" href="<?= $disabledNext ? '#' : htmlspecialchars($nextUrl); ?>">»</a>
                        </li>
                    </ul>
                </nav>
            </div>
        <?php endif; ?>
    </div>
</div>

<script>
/**
 * -----------------------------------------------------------------------------
 * Auto-Dismiss für Hinweise (Info/Fehler/Legende)
 * -----------------------------------------------------------------------------
 */
setTimeout(function () {
    document.querySelectorAll('.auto-dismiss').forEach(function (el) {
        el.style.transition = 'opacity 400ms ease';
        el.style.opacity = '0';
        setTimeout(function () { el.remove(); }, 450);
    });
}, 7000);
</script>

<?php
$pageContent = ob_get_clean();
include_once __DIR__ . '/../template.php';
