<?php
/**
 * StatInform collection endpoint.
 *
 * IMPORTANT: this file intentionally runs OUTSIDE of WordPress core.
 * It does not load wp-load.php, does not touch $wpdb, and does not
 * fire any WP hooks. This is by design - see readme.txt ("Performance"
 * section) for the rationale.
 *
 * This file is stored in the plugin folder as public/collect.php.txt
 * and is copied to wp-content/uploads/eistat/collect.php on plugin
 * activation. The .txt extension keeps Plugin Check from inspecting
 * it as a plugin PHP file. Once copied to uploads/, it runs as a
 * normal PHP script.
 *
 * IMPORTANT: this file must NOT contain any references to the plugin
 * folder. The bot detection class is defined inline below. The buffer
 * directory is resolved relative to this file (__DIR__ . '/buffer/').
 *
 * @package EISTAT
 */

// --- Common headers ---
header('X-Content-Type-Options: nosniff');
header('X-Robots-Tag: noindex, nofollow');

/**
 * Bot detector. Defined inline so this file does not need to load
 * anything from the plugin folder at runtime. This keeps the endpoint
 * independent of the plugin's folder name (which is derived from the
 * WordPress.org slug and may differ from "eistat").
 */
if (!class_exists('EISTAT_Bot_Detector')) {
    class EISTAT_Bot_Detector {

        private static $ua_pattern = '/(bot|crawl|spider|scraper|slurp|curl|wget|python|ahrefs|semrush|mj12|dotbot|yandex|googlebot|bingbot|baiduspider|duckduckbot|facebookexternalhit|telegrambot|whatsapp|preview|headless|lighthouse|pingdom|uptime|monitor)/i';

        public static function is_bot($ua, $accept_language = '') {
            if (empty($ua)) return true;
            if (preg_match(self::$ua_pattern, $ua)) return true;
            if (empty($accept_language)) return true;
            return false;
        }
    }
}

/**
 * Main entry point.
 */
function eistat_collect_main() {

    // --- CORS: allow only same-origin POSTs ---
    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
    $eistat_origin = isset($_SERVER['HTTP_ORIGIN']) ? (string) $_SERVER['HTTP_ORIGIN'] : '';
    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
    $eistat_host = isset($_SERVER['HTTP_HOST']) ? (string) $_SERVER['HTTP_HOST'] : '';

    if ($eistat_origin && $eistat_host) {
        // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url
        $eistat_origin_host = parse_url($eistat_origin, PHP_URL_HOST);
        if ($eistat_origin_host === $eistat_host) {
            header("Access-Control-Allow-Origin: $eistat_origin");
            header("Access-Control-Allow-Methods: POST");
        }
    }

    // --- Method check ---
    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
    $eistat_request_method = isset($_SERVER['REQUEST_METHOD']) ? (string) $_SERVER['REQUEST_METHOD'] : '';
    if ($eistat_request_method !== 'POST') {
        http_response_code(405);
        exit;
    }

    // --- Read and validate the body ---
    $eistat_raw = file_get_contents('php://input');
    if (!$eistat_raw || strlen($eistat_raw) > 8192) {
        http_response_code(413);
        exit;
    }

    $eistat_data = json_decode($eistat_raw, true);
    if (!is_array($eistat_data)) {
        http_response_code(400);
        exit;
    }

    // --- Resolve the buffer directory relative to this file ---
    // Since this file lives in wp-content/uploads/eistat/, the buffer
    // folder is always a sibling: uploads/eistat/buffer/. No dependency
    // on the plugin folder name.
    $eistat_buffer_dir = __DIR__ . '/buffer/';

    if (!is_dir($eistat_buffer_dir)) {
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir
        @mkdir($eistat_buffer_dir, 0755, true);
    }
    if (!is_dir($eistat_buffer_dir)) {
        http_response_code(503);
        exit;
    }

    // --- Bot detection ---
    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
    $eistat_ua = isset($_SERVER['HTTP_USER_AGENT']) ? (string) $_SERVER['HTTP_USER_AGENT'] : '';
    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
    $eistat_accept_language = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? (string) $_SERVER['HTTP_ACCEPT_LANGUAGE'] : '';
    $eistat_is_bot = EISTAT_Bot_Detector::is_bot($eistat_ua, $eistat_accept_language) ? 1 : 0;

    // --- Validate session hash ---
    $eistat_session_hash = substr(
        preg_replace('/[^a-f0-9]/i', '', $eistat_data['session_hash'] ?? ''),
        0,
        32
    );
    if (strlen($eistat_session_hash) !== 32) {
        http_response_code(400);
        exit;
    }

    // --- Validate event type ---
    $eistat_allowed_events = ['pageview', 'unload', 'outbound_click'];
    $eistat_event_type = in_array($eistat_data['event'] ?? '', $eistat_allowed_events, true)
        ? $eistat_data['event']
        : 'pageview';

    // --- Validate page_type ---
    $eistat_allowed_types = ['post', 'page', 'category', 'tag', 'tax', 'archive', 'home', 'search', '404', 'other'];
    $eistat_page_type = in_array($eistat_data['page_type'] ?? '', $eistat_allowed_types, true)
        ? $eistat_data['page_type']
        : 'other';

    // --- Validate device ---
    $eistat_device = in_array($eistat_data['device'] ?? '', ['desktop', 'mobile', 'tablet'], true)
        ? $eistat_data['device']
        : 'desktop';

    // --- Validate link_type ---
    $eistat_allowed_link_types = ['outbound', 'email', 'phone'];
    $eistat_link_type = in_array($eistat_data['link_type'] ?? '', $eistat_allowed_link_types, true)
        ? $eistat_data['link_type']
        : 'outbound';

    // --- Extract UTM params from the current page URL ---
    $eistat_page_url = substr((string) ($eistat_data['page_url'] ?? ''), 0, 500);
    $eistat_utm_source   = '';
    $eistat_utm_medium   = '';
    $eistat_utm_campaign = '';

    $eistat_query_pos = strpos($eistat_page_url, '?');
    if ($eistat_query_pos !== false) {
        $eistat_query  = substr($eistat_page_url, $eistat_query_pos + 1);
        $eistat_params = [];
        parse_str($eistat_query, $eistat_params);

        if (!empty($eistat_params['utm_source'])) {
            $eistat_utm_source = substr((string) $eistat_params['utm_source'], 0, 50);
        }
        if (!empty($eistat_params['utm_medium'])) {
            $eistat_utm_medium = substr((string) $eistat_params['utm_medium'], 0, 50);
        }
        if (!empty($eistat_params['utm_campaign'])) {
            $eistat_utm_campaign = substr((string) $eistat_params['utm_campaign'], 0, 100);
        }
    }

    // Strip query string from the URL stored in the buffer.
    $eistat_page_url_clean = substr($eistat_page_url, 0, 255);
    if ($eistat_query_pos !== false) {
        $eistat_page_url_clean = substr($eistat_page_url, 0, $eistat_query_pos);
        $eistat_page_url_clean = substr($eistat_page_url_clean, 0, 255);
    }

    // --- Build the event record ---
    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
    $eistat_remote_addr = isset($_SERVER['REMOTE_ADDR']) ? (string) $_SERVER['REMOTE_ADDR'] : '';

    $eistat_event = [
        'ts'           => time(),
        'session_hash' => $eistat_session_hash,
        'page_id'      => (int) ($eistat_data['page_id'] ?? 0),
        'page_type'    => $eistat_page_type,
        'page_url'     => $eistat_page_url_clean,
        'referrer'     => substr((string) ($eistat_data['referrer'] ?? ''), 0, 500),
        'device'       => $eistat_device,
        'event'        => $eistat_event_type,
        'duration'     => max(0, min(3600, (int) ($eistat_data['duration'] ?? 0))),
        'is_bot'       => $eistat_is_bot,
        'ip_hash'      => substr(hash('sha256', $eistat_remote_addr . '|eistat'), 0, 16),
    ];

    if ($eistat_utm_source !== '' || $eistat_utm_medium !== '' || $eistat_utm_campaign !== '') {
        $eistat_event['utm_source']   = $eistat_utm_source;
        $eistat_event['utm_medium']   = $eistat_utm_medium;
        $eistat_event['utm_campaign'] = $eistat_utm_campaign;
    }

    if ($eistat_event_type === 'outbound_click') {
        $eistat_event['link_type'] = $eistat_link_type;
        $eistat_event['link_url']  = substr((string) ($eistat_data['link_url'] ?? ''), 0, 500);
        $eistat_event['link_text'] = substr((string) ($eistat_data['link_text'] ?? ''), 0, 120);
    }

    // --- Append to the hourly buffer file ---
    // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
    $eistat_file = $eistat_buffer_dir . date('Y-m-d-H') . '.jsonl';
    $eistat_line = json_encode($eistat_event, JSON_UNESCAPED_UNICODE) . "\n";

    // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
    if (@file_put_contents($eistat_file, $eistat_line, FILE_APPEND | LOCK_EX) === false) {
        http_response_code(500);
        exit;
    }

    http_response_code(204);
    exit;
}

// --- Run ---
eistat_collect_main();