<?php
if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * REST API: /vlens/v1/track
 * Receives visitor pageview data from tracker.js.
 */
class VLENS_REST_Track {

    public function register_routes() {
        register_rest_route( 'vlens/v1', '/track', [
            'methods'             => 'POST',
            'callback'            => [ $this, 'handle' ],
            // Intentionally public — anonymous visitor pageview beacon (no login involved).
            // Guarded against cross-origin forgery and per-IP flooding in VLENS_Helpers::public_write_permission().
            'permission_callback' => function ( WP_REST_Request $request ) {
                return VLENS_Helpers::public_write_permission( $request, 'track' );
            },
        ] );
    }

    public function handle( WP_REST_Request $request ) {
        global $wpdb;

        $data = $request->get_json_params();
        if ( empty( $data ) ) {
            return new WP_REST_Response( [ 'error' => 'Invalid payload' ], 400 );
        }

        $ip_raw     = VLENS_Helpers::get_real_ip();
        $ip_hash    = VLENS_Helpers::hash_ip( $ip_raw );
        $today      = current_time( 'Y-m-d' );
        $now        = current_time( 'mysql' );
        $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
        $is_bot     = preg_match( '/bot|crawl|slurp|spider|headless|phantom/i', $user_agent ) ? 1 : 0;
        $wp_user_id = get_current_user_id(); // 0 for anonymous visitors

        // Fields from JS payload
        $page_uri    = VLENS_Helpers::sanitize_str( $data['page_uri'] ?? '/', 2000 );
        $page_title  = VLENS_Helpers::sanitize_str( $data['page_title'] ?? '', 500 );
        $referrer    = VLENS_Helpers::sanitize_str( $data['referrer'] ?? '', 2000 );
        $language    = VLENS_Helpers::sanitize_str( $data['language'] ?? '', 10 );
        $timezone    = VLENS_Helpers::sanitize_str( $data['timezone'] ?? '', 60 );
        $screen_w    = isset( $data['screen_width'] )  ? absint( $data['screen_width'] )  : 0;
        $screen_h    = isset( $data['screen_height'] ) ? absint( $data['screen_height'] ) : 0;
        $device_type = in_array( $data['device_type'] ?? '', [ 'desktop', 'mobile', 'tablet' ], true )
                       ? $data['device_type'] : 'unknown';

        $utm_source    = VLENS_Helpers::sanitize_str( $data['utm_source'] ?? '', 200 );
        $utm_medium    = VLENS_Helpers::sanitize_str( $data['utm_medium'] ?? '', 200 );
        $utm_campaign  = VLENS_Helpers::sanitize_str( $data['utm_campaign'] ?? '', 200 );
        $utm_term      = VLENS_Helpers::sanitize_str( $data['utm_term'] ?? '', 200 );
        $utm_content   = VLENS_Helpers::sanitize_str( $data['utm_content'] ?? '', 200 );
        $load_time_ms  = isset( $data['load_time_ms'] ) ? absint( $data['load_time_ms'] ) : null;

        // Tracking cookie — 32-char lowercase hex sent by tracker.js (vlens_vid)
        $raw_cookie = $data['cookie_id'] ?? '';
        $cookie_id  = ( is_string( $raw_cookie ) && preg_match( '/^[0-9a-f]{32}$/', $raw_cookie ) )
                      ? $raw_cookie
                      : null;

        [ $browser, $browser_version ] = VLENS_Helpers::parse_browser( $user_agent );
        $platform = VLENS_Helpers::parse_platform( $user_agent );
        [ $referrer_host, $referrer_type, $search_engine, $search_query ] = VLENS_Helpers::parse_referrer( $referrer );

        // GeoIP
        $geo = VLENS_Helpers::geoip_lookup( $ip_raw );
        $country_code = $geo['country_code'] ?? '--';
        $country_name = $geo['country_name'] ?? '';
        $city         = $geo['city'] ?? '';
        $region       = $geo['region'] ?? '';
        // Use 0.0 as "unknown" sentinel — avoids wpdb::prepare() deprecation for null %f in WP 6.2+
        $latitude     = isset( $geo['latitude'] )  ? (float) $geo['latitude']  : 0.0;
        $longitude    = isset( $geo['longitude'] ) ? (float) $geo['longitude'] : 0.0;

        $t_visitors = VLENS_Helpers::table( 'visitors' );
        $t_visits   = VLENS_Helpers::table( 'visits' );
        $t_daily    = VLENS_Helpers::table( 'daily_summary' );
        $t_countries= VLENS_Helpers::table( 'countries' );
        $t_browsers = VLENS_Helpers::table( 'browsers' );
        $t_platforms= VLENS_Helpers::table( 'platforms' );
        $t_referrers= VLENS_Helpers::table( 'referrers' );
        $t_search   = VLENS_Helpers::table( 'search_engines' );
        $t_online   = VLENS_Helpers::table( 'online' );
        $t_sessions = VLENS_Helpers::table( 'sessions' );

        // ── Resolve cookie_id inheritance ────────────────────────────────────
        // If the cookie matches a prior visitor row with a DIFFERENT IP,
        // we still use the same cookie_id to link them (IP rotation / mobile).
        // The unique key (ip, date) ensures today's row is per-IP-per-day;
        // cookie_id ties all those rows back to one real person.
        if ( $cookie_id && ! $wp_user_id ) {
            // Inherit wp_user_id from the most recent row with this cookie, if any
            $prior_uid = (int) $wpdb->get_var( $wpdb->prepare(
                "SELECT wp_user_id FROM %i WHERE cookie_id = %s AND wp_user_id > 0
                 ORDER BY created_at DESC LIMIT 1",
                $t_visitors, $cookie_id
            ) );
            if ( $prior_uid > 0 ) {
                $wp_user_id = $prior_uid;
            }
        }

        // Upsert visitor (one row per ip+date; cookie_id stored so we can group across IPs/days)
        $wpdb->query( $wpdb->prepare(
            "INSERT INTO %i
                (date, ip, ip_raw, referred, agent, platform, browser, browser_version,
                 device_type, country_code, country_name, city, region,
                 latitude, longitude, language, timezone, screen_width, screen_height,
                 is_bot, wp_user_id, cookie_id, created_at)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %f, %f, %s, %s, %d, %d, %d, %d, %s, %s)
            ON DUPLICATE KEY UPDATE
                ip_raw = VALUES(ip_raw), agent = VALUES(agent), browser = VALUES(browser),
                browser_version = VALUES(browser_version), device_type = VALUES(device_type),
                country_code = VALUES(country_code), country_name = VALUES(country_name),
                city = VALUES(city), region = VALUES(region),
                latitude = VALUES(latitude), longitude = VALUES(longitude),
                language = VALUES(language), timezone = VALUES(timezone),
                screen_width = VALUES(screen_width), screen_height = VALUES(screen_height),
                is_bot = VALUES(is_bot),
                wp_user_id = IF(VALUES(wp_user_id) > 0, VALUES(wp_user_id), wp_user_id),
                cookie_id  = IF(cookie_id IS NULL AND VALUES(cookie_id) IS NOT NULL, VALUES(cookie_id), cookie_id)",
            $t_visitors,
            $today, $ip_hash, $ip_raw, $referrer, $user_agent, $platform, $browser, $browser_version,
            $device_type, $country_code, $country_name, $city, $region,
            $latitude, $longitude, $language, $timezone, $screen_w, $screen_h,
            $is_bot, $wp_user_id, $cookie_id, $now
        ) );

        // rows_affected: 1 = new visitor inserted, 2 = existing visitor updated, 0 = no change
        $is_new_visitor = ( $wpdb->rows_affected === 1 );

        $visitor_id = $wpdb->insert_id;
        if ( ! $visitor_id ) {
            $visitor_id = (int) $wpdb->get_var( $wpdb->prepare(
                "SELECT id FROM %i WHERE ip = %s AND date = %s LIMIT 1",
                $t_visitors, $ip_hash, $today
            ) );
        }

        // Record page view
        $visit_data = [
            'visitor_id'    => $visitor_id,
            'date'          => $today,
            'page_uri'      => $page_uri,
            'page_title'    => $page_title,
            'referrer'      => $referrer,
            'referrer_host' => $referrer_host,
            'referrer_type' => $referrer_type,
            'search_engine' => $search_engine,
            'search_query'  => $search_query,
            'utm_source'    => $utm_source,
            'utm_medium'    => $utm_medium,
            'utm_campaign'  => $utm_campaign,
            'utm_term'      => $utm_term,
            'utm_content'   => $utm_content,
            'created_at'    => $now,
        ];
        if ( $load_time_ms !== null && $load_time_ms > 0 ) {
            $visit_data['load_time_ms'] = $load_time_ms;
        }
        $wpdb->insert( $t_visits, $visit_data );

        // recorder.js (gated by vlens_recording_enabled) is normally what creates
        // vs_sessions rows. Session Replay, WooCommerce order/cart linking, and
        // premium's Ad Lens all key their lookups off vs_sessions — so when the
        // recorder is turned off, none of those features had anything to join on,
        // even though the pageview itself (this table) was tracked correctly. Create
        // a lightweight, recording-less session row per pageview in that case so
        // those features keep working; recorder.js owns the row otherwise.
        if ( get_option( 'vlens_recording_enabled', '1' ) !== '1' ) {
            $wpdb->insert( $t_sessions, [
                'visitor_id'  => $visitor_id,
                'session_key' => wp_generate_uuid4(),
                'date'        => $today,
                'page_uri'    => $page_uri,
                'page_title'  => $page_title,
                'is_complete' => 1,
                'started_at'  => $now,
            ] );
        }

        // Daily summary — increment visitors only for new unique visitors
        if ( $is_new_visitor ) {
            $wpdb->query( $wpdb->prepare(
                "INSERT INTO %i (date, visitors, visits, page_views) VALUES (%s, 1, 1, 1)
                 ON DUPLICATE KEY UPDATE visitors = visitors + 1, page_views = page_views + 1",
                $t_daily, $today
            ) );
        } else {
            $wpdb->query( $wpdb->prepare(
                "INSERT INTO %i (date, visitors, visits, page_views) VALUES (%s, 0, 1, 1)
                 ON DUPLICATE KEY UPDATE page_views = page_views + 1",
                $t_daily, $today
            ) );
        }

        // Country
        if ( $country_code !== '--' ) {
            $wpdb->query( $wpdb->prepare(
                "INSERT INTO %i (date, country_code, country_name, visitors) VALUES (%s, %s, %s, 1)
                 ON DUPLICATE KEY UPDATE visitors = visitors + 1",
                $t_countries, $today, $country_code, $country_name
            ) );
        }

        // Browser
        $wpdb->query( $wpdb->prepare(
            "INSERT INTO %i (date, browser, version, visitors) VALUES (%s, %s, %s, 1)
             ON DUPLICATE KEY UPDATE visitors = visitors + 1",
            $t_browsers, $today, $browser, $browser_version
        ) );

        // Platform
        $wpdb->query( $wpdb->prepare(
            "INSERT INTO %i (date, platform, visitors) VALUES (%s, %s, 1)
             ON DUPLICATE KEY UPDATE visitors = visitors + 1",
            $t_platforms, $today, $platform
        ) );

        // Referrer
        if ( $referrer_host ) {
            $wpdb->query( $wpdb->prepare(
                "INSERT INTO %i (date, host, url, visits) VALUES (%s, %s, %s, 1)
                 ON DUPLICATE KEY UPDATE visits = visits + 1",
                $t_referrers, $today, $referrer_host, $referrer
            ) );
        }

        // Search engine
        if ( $search_engine ) {
            $wpdb->query( $wpdb->prepare(
                "INSERT INTO %i (date, engine, query, visits) VALUES (%s, %s, %s, 1)
                 ON DUPLICATE KEY UPDATE visits = visits + 1",
                $t_search, $today, $search_engine, $search_query
            ) );
        }

        // Online tracking
        $wpdb->query( $wpdb->prepare(
            "INSERT INTO %i (visitor_id, ip_hash, ip_raw, page_uri, last_seen)
             VALUES (%d, %s, %s, %s, NOW())
             ON DUPLICATE KEY UPDATE ip_raw = VALUES(ip_raw), page_uri = VALUES(page_uri), last_seen = NOW()",
            $t_online, $visitor_id, $ip_hash, $ip_raw, $page_uri
        ) );

        $wpdb->query( $wpdb->prepare( "DELETE FROM %i WHERE last_seen < DATE_SUB(NOW(), INTERVAL 5 MINUTE)", $t_online ) );

        $online_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM %i", $t_online ) );

        // Fire hook after pageview tracked
        do_action( 'vlens_visit_tracked', $visitor_id, $visit_data );

        return new WP_REST_Response( [
            'status'     => 200,
            'message'    => 'ok',
            'online'     => $online_count,
            'visitor_id' => $visitor_id,
        ], 200 );
    }
}
