<?php
/**
 * WP Multi – Modul: Benutzer-Analytics
 *
 * Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
 * wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
 */

if (!defined('ABSPATH')) { exit; }

/*
 * Benutzer-Analytics mit verbesserten Sicherheits-, Performance- und Benutzerfreundlichkeits-Features
 */


// global ist nötig, weil die Plugin-Datei bei der Aktivierung innerhalb einer
// Funktion eingebunden wird und $wpdb dort sonst nicht verfügbar ist.
global $wpdb;
define('WP_MULTI_ANALYTICS_TABLE', $wpdb->prefix . 'wp_multi_user_analytics');

/**
 * Erstellt die Datenbanktabelle für Benutzer-Analytics.
 */
function wp_multi_create_analytics_table() {
    global $wpdb;
    $table_name = WP_MULTI_ANALYTICS_TABLE;
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE $table_name (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        user_id bigint(20) NOT NULL,
        action varchar(255) NOT NULL,
        post_id bigint(20) DEFAULT NULL,
        timestamp datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY  (id),
        INDEX idx_timestamp (timestamp),
        INDEX idx_action (action)
    ) $charset_collate;";

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta($sql);
}
register_activation_hook(WP_MULTI_FILE, 'wp_multi_create_analytics_table');

/**
 * Verfolgt Benutzerinteraktionen (Kommentare und Beitragsaufrufe).
 *
 * @param int    $user_id Benutzer-ID.
 * @param string $action  Aktion (z. B. 'view', 'comment').
 * @param int    $post_id Beitrag-ID (optional).
 * @return bool Erfolg der Operation.
 */
function wp_multi_track_user_activity($user_id, $action, $post_id = null) {
    global $wpdb;
    $table_name = WP_MULTI_ANALYTICS_TABLE;

    $user_id = absint($user_id);
    $action = sanitize_text_field($action);
    $post_id = $post_id ? absint($post_id) : null;

    if ($action === 'view' && is_single()) {
        $post_id = get_the_ID();
    }

    // user_id 0 ist gewollt: Die Seite bietet keinen Login, Aufrufe sind anonym.
    if (!$action) {
        return false;
    }

    return $wpdb->insert(
        $table_name,
        array(
            'user_id'   => $user_id,
            'action'    => $action,
            'post_id'   => $post_id,
        ),
        array('%d', '%s', '%d')
    );
}

/**
 * Verfolgt Kommentar-Aktivitäten.
 *
 * @param int $comment_id Kommentar-ID.
 */
function wp_multi_comment_activity($comment_id) {
    $comment = get_comment($comment_id);
    $user_id = absint($comment->user_id);
    if ($user_id) {
        wp_multi_track_user_activity($user_id, 'comment', $comment->comment_post_ID);
    }
}
add_action('comment_post', 'wp_multi_comment_activity');

/**
 * Erkennt Bots und Crawler anhand des User-Agents.
 *
 * @return bool
 */
function wp_multi_is_bot_request() {
    $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower(sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT']))) : '';

    // Ohne User-Agent ist es so gut wie nie ein echter Besucher
    if ($user_agent === '') {
        return true;
    }

    $signatures = apply_filters('wp_multi_bot_signatures', [
        'bot', 'crawl', 'spider', 'slurp', 'archiver', 'preview', 'monitor', 'validator',
        'facebookexternalhit', 'headless', 'phantomjs', 'python', 'curl', 'wget', 'go-http',
        'java/', 'okhttp', 'axios', 'scrapy', 'lighthouse', 'pingdom', 'uptime',
    ]);

    foreach ($signatures as $signature) {
        if (strpos($user_agent, $signature) !== false) {
            return true;
        }
    }

    return false;
}

/**
 * Prüft, ob dieser Besucher den Beitrag gerade erst aufgerufen hat.
 *
 * Ohne Login gibt es keine Benutzer-ID, deshalb dient ein kurzlebiger Hash aus
 * IP und User-Agent als Erkennungsmerkmal. Gespeichert wird nur der Hash, nie
 * die IP selbst – ein Reload zählt damit nicht mehrfach.
 *
 * @param int $post_id Beitrag-ID.
 * @return bool True, wenn der Aufruf bereits gezählt wurde.
 */
function wp_multi_view_already_counted($post_id) {
    $ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
    $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';

    $key = 'wp_multi_view_' . md5($post_id . '|' . $ip . '|' . $user_agent . '|' . wp_salt());

    if (get_transient($key)) {
        return true;
    }

    // Sperrfrist je Besucher und Beitrag
    $ttl = (int) apply_filters('wp_multi_view_throttle', 30 * MINUTE_IN_SECONDS);
    set_transient($key, 1, $ttl);

    return false;
}

/**
 * Verfolgt Beitragsaufrufe – auch von nicht eingeloggten Besuchern.
 */
function wp_multi_post_view_activity() {
    if (is_admin() || !is_single() || is_feed()) {
        return;
    }

    // Eigene Aufrufe der Redaktion verfälschen die Zahlen
    if (is_user_logged_in() && current_user_can('edit_posts') && !apply_filters('wp_multi_track_editor_views', false)) {
        return;
    }

    if (wp_multi_is_bot_request()) {
        return;
    }

    $post_id = get_the_ID();
    if (!$post_id || wp_multi_view_already_counted($post_id)) {
        return;
    }

    // Ohne Login ist die Benutzer-ID 0 – der Aufruf zählt trotzdem
    wp_multi_track_user_activity(get_current_user_id(), 'view', $post_id);
}
add_action('wp_head', 'wp_multi_post_view_activity');

/**
 * Baut die WHERE-Bedingung für den gewählten Zeitraum.
 *
 * @return array [WHERE-Fragment, Parameter]
 */
function wp_multi_analytics_date_where($start_datetime = null, $end_datetime = null) {
    if (!$start_datetime) {
        $start_datetime = gmdate('Y-m-d H:i:s', strtotime('-7 days'));
    }

    $where = 'WHERE timestamp >= %s';
    $params = [$start_datetime];

    if ($end_datetime) {
        $where .= ' AND timestamp <= %s';
        $params[] = $end_datetime;
    }

    return [$where, $params];
}

/**
 * Ruft die Tagessummen je Aktion ab – Grundlage für das Diagramm.
 *
 * Aggregiert in der Datenbank statt in PHP: Seit auch anonyme Aufrufe gezählt
 * werden, kämen hier sonst zehntausende Einzelzeilen an.
 *
 * @return array Zeilen mit date, action und count.
 */
function wp_multi_fetch_analytics_totals($start_datetime = null, $end_datetime = null) {
    global $wpdb;

    list($where, $params) = wp_multi_analytics_date_where($start_datetime, $end_datetime);

    $sql = "SELECT DATE(timestamp) AS date, action, COUNT(*) AS count
             FROM " . WP_MULTI_ANALYTICS_TABLE . "
             $where
             GROUP BY date, action
             ORDER BY date ASC";

    return $wpdb->get_results($wpdb->prepare($sql, $params));
}

/**
 * Ruft die jüngsten Einzelereignisse ab – Grundlage für die Detailtabelle.
 *
 * @return array Rohe Analytics-Daten (begrenzt).
 */
function wp_multi_fetch_raw_analytics($start_datetime = null, $end_datetime = null) {
    global $wpdb;

    list($where, $params) = wp_multi_analytics_date_where($start_datetime, $end_datetime);

    // Ohne Limit würde die Detailtabelle bei anonymem Tracking die Seite sprengen
    $params[] = (int) apply_filters('wp_multi_analytics_detail_limit', 200);

    $sql = "SELECT DATE(timestamp) AS date, action, post_id, 1 AS count, user_id, timestamp
             FROM " . WP_MULTI_ANALYTICS_TABLE . "
             $where
             ORDER BY timestamp DESC
             LIMIT %d";

    return $wpdb->get_results($wpdb->prepare($sql, $params));
}

/**
 * Verarbeitet rohe Analytics-Daten für Diagramm und Tabelle.
 *
 * @param array $results Rohe Analytics-Daten.
 * @return array Verarbeitete Daten.
 */
function wp_multi_process_analytics_data($results, $recent = null) {
    $dates = [];
    $comment_counts = [];
    $view_counts = [];

    foreach ($results as $result) {
        $date = $result->date;
        if (!in_array($date, $dates)) {
            $dates[] = $date;
        }
        if ($result->action === 'comment') {
            $comment_counts[$date] = ($comment_counts[$date] ?? 0) + $result->count;
        } elseif ($result->action === 'view') {
            $view_counts[$date] = ($view_counts[$date] ?? 0) + $result->count;
        }
    }

    $all_dates = [];
    $datasets = ['comments' => [], 'views' => []];

    for ($i = 6; $i >= 0; $i--) {
        $date = date('Y-m-d', strtotime("-$i day"));
        $all_dates[] = $date;
        $datasets['comments'][] = $comment_counts[$date] ?? 0;
        $datasets['views'][] = $view_counts[$date] ?? 0;
    }

    return [
        'dates' => array_reverse($all_dates),
        'datasets' => [
            [
                'label' => __('Kommentare', 'wp-multi'),
                'data' => array_reverse($datasets['comments']),
                'borderColor' => 'rgba(75, 192, 192, 1)',
                'borderWidth' => 1,
                'fill' => false,
            ],
            [
                'label' => __('Beitragsaufrufe', 'wp-multi'),
                'data' => array_reverse($datasets['views']),
                'borderColor' => 'rgba(153, 102, 255, 1)',
                'borderWidth' => 1,
                'fill' => false,
            ]
        ],
        'data' => ($recent === null) ? $results : $recent
    ];
}

/**
 * Ruft Analytics-Daten mit Caching ab.
 *
 * @param string $date_query Datum für die Abfrage.
 * @return array Analytics-Daten.
 */
function wp_multi_get_analytics_data($start_datetime = null, $end_datetime = null) {
    $cache_key = 'wp_multi_analytics_data_' . md5($start_datetime . '|' . $end_datetime);
    $cached_data = get_transient($cache_key);

    if ($cached_data !== false) {
        return $cached_data;
    }

    $totals = wp_multi_fetch_analytics_totals($start_datetime, $end_datetime);
    $recent = wp_multi_fetch_raw_analytics($start_datetime, $end_datetime);
    $data = wp_multi_process_analytics_data($totals, $recent);

    set_transient($cache_key, $data, HOUR_IN_SECONDS);
    return $data;
}

/**
 * Zeigt die Benutzer-Analytics-Seite im Admin-Bereich an.
 */
function wp_multi_display_user_analytics() {
    global $wpdb;

    if (!$wpdb->get_var("SHOW TABLES LIKE '" . WP_MULTI_ANALYTICS_TABLE . "'")) {
        echo '<div class="error"><p>' . esc_html__('Die Analytics-Tabelle existiert nicht. Bitte aktiviere das Plugin erneut.', 'wp-multi') . '</p></div>';
        return;
    }

    $time_range = isset($_GET['time_range']) ? sanitize_text_field($_GET['time_range']) : '7days';
    $start_datetime = gmdate('Y-m-d H:i:s', strtotime('-7 days'));
    $end_datetime = null;

    if ($time_range === '30days') {
        $start_datetime = gmdate('Y-m-d H:i:s', strtotime('-30 days'));
    } elseif ($time_range === 'custom' && isset($_GET['start_date'], $_GET['end_date'])) {
        $custom_start = sanitize_text_field(wp_unslash($_GET['start_date']));
        $custom_end   = sanitize_text_field(wp_unslash($_GET['end_date']));
        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $custom_start) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $custom_end)) {
            $start_datetime = $custom_start . ' 00:00:00';
            $end_datetime = $custom_end . ' 23:59:59';
        }
    }

    $results = wp_multi_get_analytics_data($start_datetime, $end_datetime);

    wpmt_admin_page_open(
        __('Benutzer Analytics', 'wp-multi'),
        __('Beitragsaufrufe und Kommentar-Aktivität deiner Besucher', 'wp-multi')
    );

    wpmt_admin_card_open(__('Zeitraum', 'wp-multi'));
    ?>
    <form method="get">
        <input type="hidden" name="page" value="wp_multi_analytics">
        <select name="time_range" onchange="this.form.submit()" style="max-width:240px;">
            <option value="7days" <?php selected($time_range, '7days'); ?>><?php esc_html_e('Letzte 7 Tage', 'wp-multi'); ?></option>
            <option value="30days" <?php selected($time_range, '30days'); ?>><?php esc_html_e('Letzte 30 Tage', 'wp-multi'); ?></option>
            <option value="custom" <?php selected($time_range, 'custom'); ?>><?php esc_html_e('Benutzerdefiniert', 'wp-multi'); ?></option>
        </select>
        <?php if ($time_range === 'custom') : ?>
            <input type="date" name="start_date" value="<?php echo esc_attr($_GET['start_date'] ?? ''); ?>" style="max-width:180px;">
            <input type="date" name="end_date" value="<?php echo esc_attr($_GET['end_date'] ?? ''); ?>" style="max-width:180px;">
        <?php endif; ?>
        <button type="submit" class="wpm-btn wpm-btn--primary"><?php esc_html_e('Filtern', 'wp-multi'); ?></button>
    </form>
    <?php
    wpmt_admin_card_close();

    if (empty($results['data'])) {
        wpmt_admin_notice('info', __('Keine Daten für den gewählten Zeitraum verfügbar.', 'wp-multi'));
    } else {
        wpmt_admin_card_open(__('Aktivitätsverlauf', 'wp-multi'));
        ?>
        <canvas id="userActivityChart" style="height: 300px; width: 100%;"></canvas>
        <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
        <script>
            if (typeof Chart !== 'undefined') {
                document.addEventListener('DOMContentLoaded', function () {
                    var ctx = document.getElementById('userActivityChart').getContext('2d');
                    var chart = new Chart(ctx, {
                        type: 'line',
                        data: {
                            labels: <?php echo wp_json_encode($results['dates']); ?>,
                            datasets: <?php echo wp_json_encode($results['datasets']); ?>,
                        },
                        options: {
                            scales: {
                                x: { title: { display: true, text: '<?php echo esc_js(__('Datum', 'wp-multi')); ?>' } },
                                y: { title: { display: true, text: '<?php echo esc_js(__('Anzahl', 'wp-multi')); ?>' }, beginAtZero: true }
                            }
                        }
                    });
                });
            } else {
                console.error('Chart.js konnte nicht geladen werden.');
            }
        </script>
        <?php
        wpmt_admin_card_close();

        wpmt_admin_card_open(__('Einzelne Aktivitäten', 'wp-multi'));
        ?>
        <div class="wpm-table-wrap">
            <table class="wpm-table">
                <thead>
                    <tr>
                        <th><?php esc_html_e('Benutzer ID', 'wp-multi'); ?></th>
                        <th><?php esc_html_e('Aktion', 'wp-multi'); ?></th>
                        <th><?php esc_html_e('Beitrag Titel', 'wp-multi'); ?></th>
                        <th><?php esc_html_e('Beitrag ID', 'wp-multi'); ?></th>
                        <th><?php esc_html_e('Zeitstempel', 'wp-multi'); ?></th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($results['data'] as $row) : ?>
                        <tr>
                            <td><?php echo $row->user_id ? esc_html($row->user_id) : esc_html__('Gast', 'wp-multi'); ?></td>
                            <td><span class="wpm-badge <?php echo $row->action === 'comment' ? 'wpm-badge--success' : ''; ?>"><?php echo esc_html($row->action); ?></span></td>
                            <td>
                                <?php
                                if ($row->post_id) {
                                    $post_title = get_the_title($row->post_id);
                                    echo esc_html($post_title ?: __('Kein Titel verfügbar', 'wp-multi'));
                                } else {
                                    echo esc_html__('Kein Beitrag', 'wp-multi');
                                }
                                ?>
                            </td>
                            <td><?php echo esc_html($row->post_id ?: '-'); ?></td>
                            <td><?php echo esc_html($row->timestamp); ?></td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        </div>
        <?php
        wpmt_admin_card_close();
    }

    wpmt_admin_page_close();
}

// Der Analytics-Menüpunkt wird zentral in wp_multi_register_admin_menus() registriert.








