<?php

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

if ( class_exists( 'AIEO_Session_Tracker' ) ) {
    return;
}

class AIEO_Session_Tracker {

    
    private static $instance = null;

    
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    
    private function __construct() {
        
        add_action('rest_api_init', array($this, 'register_routes'));

        
        add_action('wp_enqueue_scripts', array($this, 'enqueue_tracking_script'));

        
        add_filter('cron_schedules', array($this, 'add_custom_cron_schedules'));

        
        add_action('aieo_cleanup_old_sessions', array($this, 'cleanup_old_sessions'));
        add_action('aieo_archive_sessions', array($this, 'archive_sessions'));

        
        
        
        if ( (int) get_option( 'aieo_session_archive_rolling_v', 0 ) < 1 ) {
            update_option( 'aieo_session_archive_frequency', 'daily', false );
            $this->schedule_archive_cron();
            update_option( 'aieo_session_archive_rolling_v', 1, false );
        }

        
        if (!wp_next_scheduled('aieo_archive_sessions')) {
            $this->schedule_archive_cron();
        }
    }

    
    public function add_custom_cron_schedules($schedules) {
        
        if (!isset($schedules['weekly'])) {
            $schedules['weekly'] = array(
                'interval' => 604800, 
                'display' => __('Once Weekly', 'ai-eshop-optimizer')
            );
        }

        
        if (!isset($schedules['monthly'])) {
            $schedules['monthly'] = array(
                'interval' => 2592000, 
                'display' => __('Once Monthly', 'ai-eshop-optimizer')
            );
        }

        return $schedules;
    }

    
    public function cleanup_old_sessions() {
        global $wpdb;
        $archive_table = $wpdb->prefix . 'aieo_sessions_archive';
        $archive_statics_table = $wpdb->prefix . 'aieo_sessions_statics_archive';
        $retention_days = (int) get_option('aieo_session_retention_days', 30);

        
        
        $deleted_events = $wpdb->query($wpdb->prepare(
            "DELETE FROM {$archive_table} WHERE archived_at < DATE_SUB(UTC_TIMESTAMP(), INTERVAL %d DAY)",
            $retention_days
        ));

        
        $deleted_statics = $wpdb->query($wpdb->prepare(
            "DELETE FROM {$archive_statics_table} WHERE archived_at < DATE_SUB(UTC_TIMESTAMP(), INTERVAL %d DAY)",
            $retention_days
        ));

        if ($deleted_events > 0 || $deleted_statics > 0) {
            if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log("AIEO: Cleaned up archived session data - {$deleted_events} events, {$deleted_statics} sessions older than {$retention_days} days"); }
        }
    }

    
    public function schedule_archive_cron() {
        
        $timestamp = wp_next_scheduled('aieo_archive_sessions');
        if ($timestamp) {
            wp_unschedule_event($timestamp, 'aieo_archive_sessions');
        }

        
        
        
        $frequency = get_option('aieo_session_archive_frequency', 'daily');
        $hour = (int) get_option('aieo_session_archive_hour', 4);

        
        $now = current_time('timestamp', true); 
        $next_run = strtotime('today ' . sprintf('%02d:00:00', $hour), $now);

        
        if ($next_run <= $now) {
            $next_run = strtotime('tomorrow ' . sprintf('%02d:00:00', $hour), $now);
        }

        
        wp_schedule_event($next_run, $frequency, 'aieo_archive_sessions');
    }

    
    public function archive_sessions() {
        
        
        
        
        if ('1' !== (string) get_option('aieo_session_tracking_enabled', '0')) {
            return;
        }
        global $wpdb;

        $sessions_table = $wpdb->prefix . 'aieo_sessions';
        $statics_table = $wpdb->prefix . 'aieo_sessions_statics';
        $archive_table = $wpdb->prefix . 'aieo_sessions_archive';
        $archive_statics_table = $wpdb->prefix . 'aieo_sessions_statics_archive';

        
        
        
        
        
        
        
        
        $event_days   = max( 1, (int) apply_filters( 'aieo_session_hot_days', (int) get_option( 'aieo_session_hot_days', 3 ) ) );
        $statics_days = max( $event_days, (int) get_option( 'aieo_session_retention_days', 30 ) );

        $now               = current_time( 'timestamp', true );
        $event_cutoff_ms   = ( $now - $event_days   * DAY_IN_SECONDS ) * 1000;
        $statics_cutoff_ms = ( $now - $statics_days * DAY_IN_SECONDS ) * 1000;

        if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( 'AIEO: rolling session prune at ' . gmdate( 'Y-m-d H:i:s', $now ) . " GMT (events>{$event_days}d, statics>{$statics_days}d)" ); }

        try {
            
            
            $wpdb->query( $wpdb->prepare(
                "INSERT INTO {$archive_table}
                (session_id, user_id, event_type, product_id, product_name, category_id, category_name,
                 scroll_depth, click_count, event_sequence, is_first_event, is_last_event, is_only_event,
                 time_on_page, visit_number, order_id, checkout_step, event_data, page_url, timestamp, created_at, archived_at)
                SELECT
                    session_id, user_id, event_type, product_id, product_name, category_id, category_name,
                    scroll_depth, click_count, event_sequence, is_first_event, is_last_event, is_only_event,
                    time_on_page, visit_number, order_id, checkout_step, event_data, page_url, timestamp, created_at, UTC_TIMESTAMP()
                FROM {$sessions_table}
                WHERE timestamp < %d",
                $event_cutoff_ms
            ) );
            $events_pruned = self::batched_delete( $sessions_table, 'timestamp', $event_cutoff_ms );

            
            
            
            
            
            
            
            
            $aieo_canon_cols = '';
            $aieo_canon_set  = array( 'landing_path', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'exit_path', 'referrer_host', 'channel', 'pages_viewed', 'value_tier' );
            
            $aieo_stat_cols = (array) $wpdb->get_col( "SHOW COLUMNS FROM {$statics_table}" );
            
            $aieo_arch_cols = (array) $wpdb->get_col( "SHOW COLUMNS FROM {$archive_statics_table}" );
            $aieo_shared    = array_values( array_intersect( $aieo_canon_set, $aieo_stat_cols, $aieo_arch_cols ) );
            if ( ! empty( $aieo_shared ) ) {
                $aieo_canon_cols = ', ' . implode( ', ', $aieo_shared );
            }
            
            $wpdb->query( $wpdb->prepare(
                "INSERT INTO {$archive_statics_table}
                (session_id, user_id, user_agent, device_type, browser, os, landing_page, referrer,
                 first_timestamp, last_timestamp, total_events, total_product_views, total_add_to_cart,
                 total_scroll_events, total_click_events, session_duration_seconds, created_at, updated_at{$aieo_canon_cols}, archived_at)
                SELECT
                    session_id, user_id, user_agent, device_type, browser, os, landing_page, referrer,
                    first_timestamp, last_timestamp, total_events, total_product_views, total_add_to_cart,
                    total_scroll_events, total_click_events, session_duration_seconds, created_at, updated_at{$aieo_canon_cols}, UTC_TIMESTAMP()
                FROM {$statics_table}
                WHERE last_timestamp < %d",
                $statics_cutoff_ms
            ) );
            $statics_pruned = self::batched_delete( $statics_table, 'last_timestamp', $statics_cutoff_ms );

            if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( "AIEO: rolling prune aged out {$events_pruned} events, {$statics_pruned} statics" ); }

            
            
            
            
            
            
            
            do_action( 'aieo_archive_run', current_time( 'mysql', true ) );

        } catch (Exception $e) {
            if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO: Session archival failed - ' . $e->getMessage()); }
        }
    }

    
    private static function batched_delete( $table, $ts_col, $cutoff_ms, $batch = 5000, $max_iter = 400 ) {
        global $wpdb;
        $total = 0;
        for ( $i = 0; $i < $max_iter; $i++ ) {
            
            $deleted = (int) $wpdb->query( $wpdb->prepare(
                "DELETE FROM {$table} WHERE {$ts_col} < %d LIMIT %d",
                $cutoff_ms,
                $batch
            ) );
            $total += $deleted;
            if ( $deleted < $batch ) { break; }
        }
        return $total;
    }

    
    public function register_routes() {
        
        
        
        
        
        
        register_rest_route('aieo/v1', '/track', array(
            'methods' => 'POST',
            'callback' => array($this, 'handle_tracking_batch'),
            'permission_callback' => '__return_true', 
        ));

        
        
        
        
        register_rest_route('aieo/v1', '/session/(?P<session_id>[a-zA-Z0-9_-]+)', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_session_context'),
            'permission_callback' => array($this, 'can_read_session_context'),
        ));
    }

    
    public function can_read_session_context($request) {
        if (current_user_can('manage_woocommerce') || current_user_can('edit_pages')) {
            return true;
        }
        $requested = (string) $request['session_id'];
        if ($requested !== '') {
            foreach (array('aieo_attr_sid', 'aieo_session_id') as $cookie_name) {
                if (!isset($_COOKIE[$cookie_name])) {
                    continue;
                }
                $own = sanitize_text_field(wp_unslash($_COOKIE[$cookie_name]));
                if ($own !== '' && hash_equals($own, $requested)) {
                    return true;
                }
            }
        }
        return new WP_Error(
            'aieo_session_forbidden',
            __('You can only read your own session context.', 'ai-eshop-optimizer'),
            array('status' => rest_authorization_required_code())
        );
    }

    
    public function enqueue_tracking_script() {
        
        
        
        
        $tracking_enabled = get_option('aieo_session_tracking_enabled', '0');
        if ($tracking_enabled != '1' && $tracking_enabled !== 1) {
            return;
        }

        
        $bypass_consent = get_option('aieo_session_bypass_consent', '1');
        $bypass_consent = ($bypass_consent == '1' || $bypass_consent === 1);

        
        if (!$bypass_consent) {
            $require_consent = get_option('aieo_session_tracking_require_consent', '1');
            $require_consent = ($require_consent == '1' || $require_consent === 1);
            if ($require_consent && !$this->user_has_given_consent()) {
                return;
            }
        }

        
        
        
        
        
        
        
        
        
        
        
        
        
        add_action('wp_footer', array($this, 'print_tracker_loader'), 99);
    }

    
    public function print_tracker_loader() {
        $version = get_option('aieo_session_tracker_version', time());
        $src     = add_query_arg('ver', rawurlencode((string) $version), plugin_dir_url(__FILE__) . '../assets/js/aieo-session-tracker.js');
        $config  = array(
            'endpoint'           => rest_url('aieo/v1/track'),
            
            'userId'             => get_current_user_id(),
            'flushInterval'      => (int) get_option('aieo_session_flush_interval', 5000),
            'trackScrollDepth'   => get_option('aieo_track_scroll_depth', '1') === '1',
            'trackClicks'        => get_option('aieo_track_clicks', '1') === '1',
            'throttleClicks'     => get_option('aieo_throttle_clicks', '1') === '1',
            'trackMouseMovement' => get_option('aieo_track_mouse_movement', '0') === '1', 
        );
        $rules       = (string) get_option('aieo_custom_image_click_rules_js', '');
        $config_json = wp_json_encode($config);
        $src_json    = wp_json_encode($src);
        ?>
<script id="aieo-session-tracker-loader" data-cfasync="false">/*aieo-session-tracker*/
window.aieoSessionConfig = <?php echo $config_json; ?>;
(function(){
    function aieoInjectTracker(){
        if (document.getElementById('aieo-session-tracker-js')) { return; }
        var s = document.createElement('script');
        s.src = <?php echo $src_json; ?>;
        s.async = true;
        s.id = 'aieo-session-tracker-js';
        if ('fetchPriority' in s) { s.fetchPriority = 'low'; }
<?php if ('' !== $rules) : ?>
        s.addEventListener('load', function(){ try { if (window.AIEO_SESSION_TRACKER) { window.AIEO_SESSION_TRACKER.customImageClickRules = function($target, self){ <?php echo $rules; ?> }; } } catch(e){} });
<?php endif; ?>
        (document.body || document.documentElement).appendChild(s);
    }
    function aieoScheduleTracker(){
        if (window.requestIdleCallback) { window.requestIdleCallback(aieoInjectTracker, { timeout: 3000 }); }
        else { window.setTimeout(aieoInjectTracker, 1200); }
    }
    if (document.readyState === 'complete') { aieoScheduleTracker(); }
    else { window.addEventListener('load', aieoScheduleTracker); }
})();
</script>
        <?php
    }

    
    public function add_defer_attribute($tag, $handle, $src) {
        
        if ($handle !== 'aieo-session-tracker') {
            return $tag;
        }

        
        if (strpos($tag, 'defer') !== false) {
            return $tag;
        }

        
        
        
        $tag = str_replace(
            ' src=',
            ' defer data-cfasync="false" data-no-optimize="1" src=',
            $tag
        );

        return $tag;
    }

    
    private function get_or_create_session_id() {
        
        if (isset($_COOKIE['aieo_session_id'])) {
            return sanitize_text_field(wp_unslash( $_COOKIE['aieo_session_id'] ));
        }

        
        $session_id = 'session_' . time() . '_' . wp_generate_password(12, false);

        
        setcookie('aieo_session_id', $session_id, time() + 1800, COOKIEPATH, COOKIE_DOMAIN);

        return $session_id;
    }

    
    public static function is_consent_blocking_writes() {
        $tracking_enabled = get_option('aieo_session_tracking_enabled', '0');
        if ($tracking_enabled !== '1' && $tracking_enabled !== 1) {
            
            
            return false;
        }
        $bypass_consent = get_option('aieo_session_bypass_consent', '1');
        if ($bypass_consent == '1' || $bypass_consent === 1) {
            return false;
        }
        $require_consent = get_option('aieo_session_tracking_require_consent', '1');
        if ($require_consent != '1' && $require_consent !== 1) {
            return false;
        }
        $inst = self::get_instance_for_consent_check();
        if (!$inst) { return false; }
        return ! $inst->user_has_given_consent();
    }

    
    private static function get_instance_for_consent_check() {
        if (method_exists(__CLASS__, 'get_instance')) {
            $inst = self::get_instance();
            if ($inst instanceof self) { return $inst; }
        }
        return null;
    }

    
    private function user_has_given_consent() {
        
        
        if (class_exists('AIEO_Consent') && AIEO_Consent::has_choice()) {
            return AIEO_Consent::allows('analytics');
        }

        

        
        if (isset($_COOKIE['cookieyes-consent'])) {
            $consent = json_decode(stripslashes(sanitize_text_field( wp_unslash( $_COOKIE['cookieyes-consent'] ) )), true);
            return isset($consent['analytics']) && $consent['analytics'] === 'yes';
        }

        
        if (isset($_COOKIE['cookie_notice_accepted']) && $_COOKIE['cookie_notice_accepted'] === 'true') {
            return true;
        }

        
        if (function_exists('cmplz_has_consent') && cmplz_has_consent('statistics')) {
            return true;
        }

        
        return get_option('aieo_session_tracking_default_consent', '1') === '1';
    }

    
    public static function is_marketing_consent_blocking() {
        $tracking_enabled = get_option('aieo_session_tracking_enabled', '0');
        if ($tracking_enabled !== '1' && $tracking_enabled !== 1) {
            return false;
        }
        $bypass_consent = get_option('aieo_session_bypass_consent', '1');
        if ($bypass_consent == '1' || $bypass_consent === 1) {
            return false;
        }
        $require_consent = get_option('aieo_session_tracking_require_consent', '1');
        if ($require_consent != '1' && $require_consent !== 1) {
            return false;
        }
        $inst = self::get_instance_for_consent_check();
        if (!$inst) { return false; }
        return ! $inst->user_has_given_marketing_consent();
    }

    
    private function user_has_given_marketing_consent() {
        
        if (class_exists('AIEO_Consent') && AIEO_Consent::has_choice()) {
            return AIEO_Consent::allows('marketing');
        }

        
        if (isset($_COOKIE['cookieyes-consent'])) {
            $consent = json_decode(stripslashes(sanitize_text_field( wp_unslash( $_COOKIE['cookieyes-consent'] ) )), true);
            if (is_array($consent)) {
                if (isset($consent['advertisement'])) { return $consent['advertisement'] === 'yes'; }
                if (isset($consent['marketing']))     { return $consent['marketing'] === 'yes'; }
            }
            return false;
        }

        
        if (isset($_COOKIE['cookie_notice_accepted']) && $_COOKIE['cookie_notice_accepted'] === 'true') {
            return true;
        }

        
        if (function_exists('cmplz_has_consent') && cmplz_has_consent('marketing')) {
            return true;
        }

        
        return get_option('aieo_session_tracking_default_consent', '1') === '1';
    }

    
    private static function aieo_memory_limit_bytes() {
        $v = trim((string) ini_get('memory_limit'));
        if ($v === '' || $v === '-1') { return 0; }
        $unit = strtolower(substr($v, -1));
        $n    = (int) $v;
        if ($unit === 'g') { return $n * 1073741824; }
        if ($unit === 'm') { return $n * 1048576; }
        if ($unit === 'k') { return $n * 1024; }
        return $n;
    }

    
    public function handle_tracking_batch(WP_REST_Request $request) {
        global $wpdb;
        $sessions_table = $wpdb->prefix . 'aieo_sessions';
        $statics_table = $wpdb->prefix . 'aieo_sessions_statics';

        
        
        
        
        
        
        $aieo_mem_enter = memory_get_peak_usage(true);

        
        
        
        
        
        $aieo_mem_limit = self::aieo_memory_limit_bytes();
        if ($aieo_mem_limit > 0 && memory_get_usage(true) > (int) ($aieo_mem_limit * 0.9)) {
            if (!defined('AIEO_TRACK_MEM_LOG') || AIEO_TRACK_MEM_LOG) {
                
                error_log(sprintf('[AIEO_TRACK_MEM] pid=%d SOFT-EARLY-OUT usage=%dMB limit=%dMB', getmypid(), (int) round(memory_get_usage(true) / 1048576), (int) round($aieo_mem_limit / 1048576)));
            }
            return new WP_REST_Response(null, 204);
        }

        
        
        
        
        
        $aieo_enabled = get_option('aieo_session_tracking_enabled', '0');
        if ($aieo_enabled != '1' && $aieo_enabled !== 1) {
            return new WP_REST_Response(array('success' => false, 'reason' => 'tracking_disabled'), 403);
        }
        if (self::is_consent_blocking_writes()) {
            return new WP_REST_Response(array('success' => false, 'reason' => 'consent_required'), 403);
        }

        
        
        
        
        
        $aieo_ip = isset($_SERVER['REMOTE_ADDR']) ? (string) $_SERVER['REMOTE_ADDR'] : '';
        if ($aieo_ip !== '') {
            $aieo_rl_cap = (int) apply_filters('aieo_track_rate_limit_per_minute', 120);
            if ($aieo_rl_cap > 0) {
                $aieo_rl_key  = 'aieo_trk_rl_' . md5($aieo_ip);
                $aieo_rl_hits = (int) get_transient($aieo_rl_key);
                if ($aieo_rl_hits >= $aieo_rl_cap) {
                    return new WP_REST_Response(array('success' => false, 'reason' => 'rate_limited'), 429);
                }
                set_transient($aieo_rl_key, $aieo_rl_hits + 1, MINUTE_IN_SECONDS);
            }
        }

        $events = $request->get_param('events');

        if (empty($events) || !is_array($events)) {
            return new WP_Error('invalid_data', __('No events provided', 'ai-eshop-optimizer'), array('status' => 400));
        }

        
        
        
        
        $aieo_max = defined('AIEO_TRACK_MAX_EVENTS') ? (int) AIEO_TRACK_MAX_EVENTS : 100;
        if ($aieo_max > 0 && count($events) > $aieo_max) {
            if (!defined('AIEO_TRACK_MEM_LOG') || AIEO_TRACK_MEM_LOG) {
                
                error_log(sprintf('[AIEO_TRACK_MEM] pid=%d capped events %d -> %d', getmypid(), count($events), $aieo_max));
            }
            $events = array_slice($events, 0, $aieo_max);
        }

        
        $session_id = sanitize_text_field($events[0]['session_id']);

        
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
        $device_info = $this->parse_user_agent($user_agent);

        
        
        
        
        
        
        
        $first_event = $events[0];
        
        $wpdb->query($wpdb->prepare(
            "INSERT IGNORE INTO {$statics_table}
                (session_id, user_agent, device_type, browser, os, landing_page, referrer, first_timestamp)
             VALUES (%s, %s, %s, %s, %s, %s, %s, %d)",
            $session_id,
            $user_agent,
            $device_info['device_type'],
            $device_info['browser'],
            $device_info['os'],
            isset($first_event['url']) ? esc_url_raw($first_event['url']) : '',
            isset($first_event['referrer']) ? esc_url_raw($first_event['referrer']) : '',
            (int) $first_event['timestamp']
        ));

        
        
        $rows = array();

        foreach ($events as $event) {
            
            if (empty($event['session_id']) || empty($event['event_type'])) {
                continue;
            }

            
            $event_data = isset($event['data']) ? $event['data'] : array();
            $product_id = isset($event_data['product_id']) ? (int) $event_data['product_id'] : null;
            $product_name = isset($event_data['product_name']) ? sanitize_text_field($event_data['product_name']) : null;
            $category_id = isset($event_data['category_id']) ? (int) $event_data['category_id'] : null;
            $category_name = isset($event_data['category_name']) ? sanitize_text_field($event_data['category_name']) : null;
            $scroll_depth = isset($event_data['scroll_depth']) ? (int) $event_data['scroll_depth'] : null;
            $click_count = isset($event_data['click_count']) ? (int) $event_data['click_count'] : null;

            
            $event_sequence = isset($event_data['event_sequence']) ? (int) $event_data['event_sequence'] : null;
            $is_first_event = isset($event_data['is_first_event']) ? (int) $event_data['is_first_event'] : 0;
            $is_last_event = isset($event_data['is_last_event']) ? (int) $event_data['is_last_event'] : 0;
            $is_only_event = ($is_first_event && $is_last_event) ? 1 : 0;
            $time_on_page = isset($event_data['time_on_page']) ? (int) $event_data['time_on_page'] : null;
            $visit_number = isset($event_data['visit_number']) ? (int) $event_data['visit_number'] : null;
            $order_id = isset($event_data['order_id']) ? (int) $event_data['order_id'] : null;
            $checkout_step = isset($event_data['checkout_step']) ? sanitize_text_field($event_data['checkout_step']) : null;

            
            
            $event_data_json = wp_json_encode($event_data);
            if (!is_string($event_data_json)) { $event_data_json = '{}'; }
            if (strlen($event_data_json) > 8192) {
                $event_data_json = wp_json_encode(array('_aieo_truncated' => 1, 'event_type' => (string) $event['event_type'], 'orig_bytes' => strlen($event_data_json)));
            }
            $page_url = isset($event['url']) ? esc_url_raw($event['url']) : '';
            if (strlen($page_url) > 2048) { $page_url = substr($page_url, 0, 2048); }

            
            
            $event_id_val = (isset($event['event_id']) && $event['event_id'] !== '')
                ? substr(sanitize_text_field($event['event_id']), 0, 36)
                : substr(md5($session_id . '|' . (int) $event['timestamp'] . '|' . sanitize_text_field($event['event_type']) . '|' . (string) $product_id), 0, 36);

            
            $rows[] = array(
                $event_id_val,
                $session_id,
                isset($event['user_id']) ? (int) $event['user_id'] : 0,
                sanitize_text_field($event['event_type']),
                $product_id, $product_name, $category_id, $category_name,
                $scroll_depth, $click_count, $event_sequence, $is_first_event, $is_last_event, $is_only_event,
                $time_on_page, $visit_number, $order_id, $checkout_step,
                $event_data_json, $page_url, (int) $event['timestamp'],
            );
        }

        if (empty($rows)) {
            return new WP_Error('no_valid_events', __('No valid events to record', 'ai-eshop-optimizer'), array('status' => 400));
        }

        
        
        $aieo_row_ph = '(%s, %s, %d, %s, %d, %s, %d, %s, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s, %s, %d)';
        $aieo_cols   = "(event_id, session_id, user_id, event_type, product_id, product_name, category_id, category_name,
                   scroll_depth, click_count, event_sequence, is_first_event, is_last_event, is_only_event,
                   time_on_page, visit_number, order_id, checkout_step, event_data, page_url, timestamp)";
        $result = true;
        foreach (array_chunk($rows, 50) as $aieo_chunk) {
            $aieo_ph_str = implode(', ', array_fill(0, count($aieo_chunk), $aieo_row_ph));
            $aieo_flat   = array();
            foreach ($aieo_chunk as $aieo_r) {
                foreach ($aieo_r as $aieo_v) { $aieo_flat[] = $aieo_v; }
            }
            
            $aieo_q = "INSERT IGNORE INTO {$sessions_table} {$aieo_cols} VALUES " . $aieo_ph_str;
            
            if ($wpdb->query($wpdb->prepare($aieo_q, $aieo_flat)) === false) { $result = false; }
        }

        if ($result === false) {
            return new WP_Error('database_error', __('Failed to save tracking data', 'ai-eshop-optimizer'), array('status' => 500));
        }

        
        $this->update_session_summary($session_id, $events);

        
        
        $this->store_checkout_timing($events, $session_id, $device_info['device_type']);

        
        
        
        
        $aieo_mem_exit = memory_get_peak_usage(true);
        $aieo_mem_delta = $aieo_mem_exit - $aieo_mem_enter;
        if ((!defined('AIEO_TRACK_MEM_LOG') || AIEO_TRACK_MEM_LOG) && ($aieo_mem_exit > 256 * 1024 * 1024 || $aieo_mem_delta > 16 * 1024 * 1024)) {
            
            error_log(sprintf(
                '[AIEO_TRACK_MEM] pid=%d enter=%dMB exit=%dMB delta=%dMB events=%d session=%s',
                getmypid(),
                (int) round($aieo_mem_enter / 1024 / 1024),
                (int) round($aieo_mem_exit / 1024 / 1024),
                (int) round($aieo_mem_delta / 1024 / 1024),
                count($rows),
                substr($session_id, 0, 12)
            ));
        }

        return rest_ensure_response(array(
            'success' => true,
            'recorded' => count($rows),
            'session_id' => $session_id
        ));
    }

    
    private function store_checkout_timing($events, $session_id, $device_type) {
        if (!is_array($events) || !function_exists('wc_get_order')) {
            return;
        }
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_checkout_timing';

        
        
        static $table_ok = null;
        if ($table_ok === null) {
            $table_ok = ((string) $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table)) === $table);
        }
        if (!$table_ok) {
            return;
        }

        $oa_table = $wpdb->prefix . 'aieo_dmm_offer_attributions';
        static $oa_ok = null;
        if ($oa_ok === null) {
            $oa_ok = ((string) $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $oa_table)) === $oa_table);
        }

        foreach ($events as $event) {
            if (empty($event['event_type']) || $event['event_type'] !== 'checkout_timing') {
                continue;
            }
            $d = (isset($event['data']) && is_array($event['data'])) ? $event['data'] : array();
            $order_id = isset($d['order_id']) ? (int) $d['order_id'] : 0;
            if ($order_id <= 0) {
                continue;
            }
            $order = wc_get_order($order_id);
            if (!$order) {
                continue;
            }

            $total  = isset($d['total_seconds'])  ? max(0, (int) $d['total_seconds'])  : 0;
            $active = isset($d['active_seconds']) ? max(0, (int) $d['active_seconds']) : 0;
            $idle   = isset($d['idle_seconds'])   ? max(0, (int) $d['idle_seconds'])   : 0;
            
            if ($active + $idle > $total) {
                $total = $active + $idle;
            }
            $steps = isset($d['step_durations']) ? wp_json_encode($d['step_durations']) : null;

            $codes      = (array) $order->get_coupon_codes();
            $has_coupon = !empty($codes) ? 1 : 0;
            $codes_str  = $has_coupon ? substr(implode(',', array_map('sanitize_text_field', $codes)), 0, 255) : null;

            
            
            
            $coupon_is_offer = 0;
            if ($has_coupon && $oa_ok) {
                $coupon_is_offer = (int) (bool) $wpdb->get_var($wpdb->prepare(
                    "SELECT 1 FROM `{$oa_table}` WHERE order_id = %d LIMIT 1",
                    $order_id
                ));
            }

            $now        = current_time('mysql', true);
            $started_at = gmdate('Y-m-d H:i:s', max(0, time() - $total));

            
            
            $wpdb->query($wpdb->prepare(
                "INSERT INTO `{$table}`
                    (order_id, session_id, total_seconds, active_seconds, idle_seconds, step_durations,
                     device_type, has_coupon, coupon_codes, coupon_is_offer, started_at, completed_at, created_at)
                 VALUES (%d, %s, %d, %d, %d, %s, %s, %d, %s, %d, %s, %s, %s)
                 ON DUPLICATE KEY UPDATE
                    total_seconds = VALUES(total_seconds),
                    active_seconds = VALUES(active_seconds),
                    idle_seconds = VALUES(idle_seconds),
                    step_durations = VALUES(step_durations),
                    device_type = VALUES(device_type),
                    has_coupon = VALUES(has_coupon),
                    coupon_codes = VALUES(coupon_codes),
                    coupon_is_offer = VALUES(coupon_is_offer)",
                $order_id, $session_id, $total, $active, $idle, $steps,
                $device_type, $has_coupon, $codes_str, $coupon_is_offer, $started_at, $now, $now
            ));
        }
    }

    
    private function update_session_summary($session_id, $events) {
        global $wpdb;
        $statics_table = $wpdb->prefix . 'aieo_sessions_statics';

        $sessions_table = $wpdb->prefix . 'aieo_sessions';

        
        
        
        
        $agg = $wpdb->get_row($wpdb->prepare(
            "SELECT COUNT(*) AS total,
                    SUM(event_type = 'product_view') AS pv,
                    SUM(event_type = 'add_to_cart')  AS atc,
                    SUM(event_type = 'scroll_depth') AS sc,
                    SUM(event_type = 'click')        AS cl,
                    MAX(timestamp)                   AS last_ts
             FROM {$sessions_table} WHERE session_id = %s",
            $session_id
        ));
        if (!$agg) { return; }
        $last = (int) $agg->last_ts;

        $wpdb->query($wpdb->prepare(
            "UPDATE {$statics_table}
             SET last_timestamp = GREATEST(COALESCE(last_timestamp, 0), %d),
                 total_events = %d,
                 total_product_views = %d,
                 total_add_to_cart = %d,
                 total_scroll_events = %d,
                 total_click_events = %d,
                 session_duration_seconds = CAST(GREATEST(0, GREATEST(COALESCE(last_timestamp, first_timestamp), %d) - first_timestamp) / 1000 AS UNSIGNED),
                 updated_at = UTC_TIMESTAMP()
             WHERE session_id = %s",
            $last,
            (int) $agg->total,
            (int) $agg->pv,
            (int) $agg->atc,
            (int) $agg->sc,
            (int) $agg->cl,
            $last,
            $session_id
        ));
    }

    
    private function parse_user_agent($user_agent) {
        $device_type = 'desktop';
        $browser = 'unknown';
        $os = 'unknown';

        
        if (preg_match('/mobile|android|iphone|ipad|ipod|blackberry|iemobile|opera mini/i', $user_agent)) {
            if (preg_match('/ipad|tablet|playbook|silk/i', $user_agent)) {
                $device_type = 'tablet';
            } else {
                $device_type = 'mobile';
            }
        }

        
        if (preg_match('/MSIE|Trident/i', $user_agent)) {
            $browser = 'Internet Explorer';
        } elseif (preg_match('/Edge/i', $user_agent)) {
            $browser = 'Microsoft Edge';
        } elseif (preg_match('/Chrome/i', $user_agent)) {
            $browser = 'Chrome';
        } elseif (preg_match('/Safari/i', $user_agent)) {
            $browser = 'Safari';
        } elseif (preg_match('/Firefox/i', $user_agent)) {
            $browser = 'Firefox';
        } elseif (preg_match('/Opera|OPR/i', $user_agent)) {
            $browser = 'Opera';
        }

        
        if (preg_match('/Windows NT 10/i', $user_agent)) {
            $os = 'Windows 10/11';
        } elseif (preg_match('/Windows NT/i', $user_agent)) {
            $os = 'Windows';
        } elseif (preg_match('/Mac OS X/i', $user_agent)) {
            $os = 'macOS';
        } elseif (preg_match('/Android/i', $user_agent)) {
            $os = 'Android';
        } elseif (preg_match('/iOS|iPhone|iPad/i', $user_agent)) {
            $os = 'iOS';
        } elseif (preg_match('/Linux/i', $user_agent)) {
            $os = 'Linux';
        }

        return array(
            'device_type' => $device_type,
            'browser' => $browser,
            'os' => $os
        );
    }

    
    public function get_session_context(WP_REST_Request $request) {
        $session_id = $request->get_param('session_id');

        if (empty($session_id)) {
            return new WP_Error('missing_session_id', __('Session ID required', 'ai-eshop-optimizer'), array('status' => 400));
        }

        $context = $this->parse_session_data($session_id);

        return rest_ensure_response($context);
    }

    
    public function parse_session_data($session_id, $time_window = 30) {
        global $wpdb;
        $table_name = $wpdb->prefix . 'aieo_sessions';
        $statics_table = $wpdb->prefix . 'aieo_sessions_statics';

        
        $cutoff_time = (time() - ($time_window * 60)) * 1000; 

        
        
        
        
        
        $events = $wpdb->get_results($wpdb->prepare(
            "SELECT e.event_type, e.event_data, e.page_url, e.timestamp,
                    s.device_type, s.browser, s.os
             FROM {$table_name} e
             LEFT JOIN {$statics_table} s ON s.session_id = e.session_id
             WHERE e.session_id = %s
             AND e.timestamp > %d
             ORDER BY e.timestamp ASC",
            $session_id,
            $cutoff_time
        ));

        if (empty($events)) {
            return array(
                'has_data' => false,
                'message' => 'No recent activity found'
            );
        }

        
        $context = array(
            'has_data' => true,
            'session_id' => $session_id,
            'device_type' => $events[0]->device_type,
            'browser' => $events[0]->browser,
            'os' => $events[0]->os,
            'viewed_products' => array(),
            'viewed_categories' => array(),
            'viewed_pages' => array(),
            'cart_additions' => array(),
            'cart_removals' => array(),
            'wishlist_additions' => array(),
            'scroll_engagement' => array(),
            'total_time_on_site' => 0,
            'page_views' => 0,
            'engagement_score' => 0,
            'first_event_time' => null,
            'last_event_time' => null
        );

        $page_timings = array(); 
        $last_page_url = null;
        $last_page_timestamp = null;

        foreach ($events as $event) {
            $data = json_decode($event->event_data, true);
            $timestamp = (int) $event->timestamp;

            if (!$context['first_event_time']) {
                $context['first_event_time'] = $timestamp;
            }
            $context['last_event_time'] = $timestamp;

            
            if ($event->page_url !== $last_page_url && $last_page_url !== null) {
                $time_spent = ($timestamp - $last_page_timestamp) / 1000; 
                if (!isset($page_timings[$last_page_url])) {
                    $page_timings[$last_page_url] = 0;
                }
                $page_timings[$last_page_url] += $time_spent;
            }
            $last_page_url = $event->page_url;
            $last_page_timestamp = $timestamp;

            
            switch ($event->event_type) {
                case 'product_view':
                    $context['viewed_products'][] = array(
                        'product_id' => isset($data['product_id']) ? (int) $data['product_id'] : 0,
                        'product_name' => isset($data['product_name']) ? $data['product_name'] : '',
                        'timestamp' => $timestamp,
                        'time_spent' => 0 
                    );
                    $context['page_views']++;
                    break;

                case 'category_view':
                    $context['viewed_categories'][] = array(
                        'category_id' => isset($data['category_id']) ? (int) $data['category_id'] : 0,
                        'category_name' => isset($data['category_name']) ? $data['category_name'] : '',
                        'timestamp' => $timestamp,
                        'time_spent' => 0
                    );
                    $context['page_views']++;
                    break;

                case 'page_view':
                    $context['viewed_pages'][] = array(
                        'page_id' => isset($data['page_id']) ? (int) $data['page_id'] : 0,
                        'page_title' => isset($data['page_title']) ? $data['page_title'] : '',
                        'page_type' => isset($data['page_type']) ? $data['page_type'] : 'unknown',
                        'timestamp' => $timestamp
                    );
                    $context['page_views']++;
                    break;

                case 'add_to_cart':
                    $context['cart_additions'][] = array(
                        'product_id' => isset($data['product_id']) ? (int) $data['product_id'] : 0,
                        'product_name' => isset($data['product_name']) ? $data['product_name'] : '',
                        'quantity' => isset($data['quantity']) ? (int) $data['quantity'] : 1,
                        'timestamp' => $timestamp
                    );
                    break;

                case 'remove_from_cart':
                    $context['cart_removals'][] = array(
                        'product_id' => isset($data['product_id']) ? (int) $data['product_id'] : 0,
                        'timestamp' => $timestamp
                    );
                    break;

                case 'add_to_wishlist':
                    $context['wishlist_additions'][] = array(
                        'product_id' => isset($data['product_id']) ? (int) $data['product_id'] : 0,
                        'timestamp' => $timestamp
                    );
                    break;

                case 'scroll_depth':
                    $page_url = $event->page_url;
                    if (!isset($context['scroll_engagement'][$page_url])) {
                        $context['scroll_engagement'][$page_url] = array(
                            'max_depth' => 0,
                            'scroll_events' => 0
                        );
                    }
                    $depth = isset($data['depth']) ? (int) $data['depth'] : 0;
                    $context['scroll_engagement'][$page_url]['max_depth'] = max(
                        $context['scroll_engagement'][$page_url]['max_depth'],
                        $depth
                    );
                    $context['scroll_engagement'][$page_url]['scroll_events']++;
                    break;

                case 'click':
                    
                    $context['engagement_score'] += 1;
                    break;
            }
        }

        
        if ($context['first_event_time'] && $context['last_event_time']) {
            $context['total_time_on_site'] = ($context['last_event_time'] - $context['first_event_time']) / 1000; 
        }

        
        foreach ($page_timings as $url => $time) {
            
            foreach ($context['viewed_products'] as &$product) {
                if (strpos($url, 'product') !== false) {
                    $product['time_spent'] = $time;
                }
            }
            foreach ($context['viewed_categories'] as &$category) {
                if (strpos($url, 'product-category') !== false) {
                    $category['time_spent'] = $time;
                }
            }
        }

        
        $context['engagement_score'] = $this->calculate_engagement_score($context);

        return $context;
    }

    
    private function calculate_engagement_score($context) {
        
        
        
        
        
        
        $avg_scroll_depth = 0.0;
        if (!empty($context['scroll_engagement'])) {
            $total_depth = 0;
            foreach ($context['scroll_engagement'] as $page_data) {
                $total_depth += $page_data['max_depth'];
            }
            $avg_scroll_depth = $total_depth / count($context['scroll_engagement']);
        }
        $time_sec = isset($context['total_time_on_site']) ? (float) $context['total_time_on_site'] : 0.0;
        
        
        $clicks   = isset($context['engagement_score']) ? (int) $context['engagement_score'] : 0;
        $views    = isset($context['viewed_products']) ? count($context['viewed_products']) : 0;
        $cart     = isset($context['cart_additions']) ? count($context['cart_additions']) : 0;

        $scroll_c = min($avg_scroll_depth * 0.40, 40);          
        $time_c   = min(($time_sec / 60) * 30, 30);             
        $click_c  = min($clicks * 4, 20);                       
        $intent_c = min(($cart / max(1, $views)) * 10, 10);     

        return (int) round(min(100, $scroll_c + $time_c + $click_c + $intent_c));
    }

    
    public function generate_chat_context_summary($session_id) {
        $context = $this->parse_session_data($session_id);

        if (!$context['has_data']) {
            return '';
        }

        $summary = array();

        
        $summary[] = sprintf(
            "USER DEVICE: %s (%s on %s)",
            ucfirst($context['device_type']),
            $context['browser'],
            $context['os']
        );

        
        if ($context['total_time_on_site'] > 0) {
            $summary[] = sprintf(
                "SESSION DURATION: %s (%d page views)",
                gmdate("i:s", $context['total_time_on_site']),
                $context['page_views']
            );
        }

        
        $summary[] = sprintf(
            "ENGAGEMENT SCORE: %d/100 (%s)",
            $context['engagement_score'],
            $this->get_engagement_level($context['engagement_score'])
        );

        
        if (!empty($context['viewed_products'])) {
            $summary[] = "\nRECENTLY VIEWED PRODUCTS:";
            foreach (array_slice($context['viewed_products'], -5) as $product) {
                $time_ago = human_time_diff($product['timestamp'] / 1000, time());
                $time_spent = $product['time_spent'] > 0 ? sprintf(" (%d seconds)", $product['time_spent']) : '';
                $summary[] = sprintf(
                    "  - %s (viewed %s ago%s)",
                    $product['product_name'],
                    $time_ago,
                    $time_spent
                );
            }
        }

        
        if (!empty($context['viewed_categories'])) {
            $summary[] = "\nCATEGORIES BROWSED:";
            foreach ($context['viewed_categories'] as $category) {
                $summary[] = sprintf("  - %s", $category['category_name']);
            }
        }

        
        if (!empty($context['cart_additions'])) {
            $summary[] = "\nCART ACTIVITY:";
            foreach ($context['cart_additions'] as $addition) {
                $time_ago = human_time_diff($addition['timestamp'] / 1000, time());
                $summary[] = sprintf(
                    "  + Added: %s (Qty: %d) %s ago",
                    $addition['product_name'],
                    $addition['quantity'],
                    $time_ago
                );
            }
        }

        if (!empty($context['cart_removals'])) {
            foreach ($context['cart_removals'] as $removal) {
                $time_ago = human_time_diff($removal['timestamp'] / 1000, time());
                $summary[] = sprintf("  - Removed product ID %d %s ago", $removal['product_id'], $time_ago);
            }
        }

        
        if (!empty($context['wishlist_additions'])) {
            $summary[] = sprintf("\nWISHLIST: %d items added", count($context['wishlist_additions']));
        }

        return implode("\n", $summary);
    }

    
    private function get_engagement_level($score) {
        if ($score >= 80) return 'Very High';
        if ($score >= 60) return 'High';
        if ($score >= 40) return 'Medium';
        if ($score >= 20) return 'Low';
        return 'Very Low';
    }
}

