<?php
/**
 * Analytics Tracking Service
 *
 * Handles real-time analytics tracking for FleekDash V2
 */

namespace FleekDash\Services;

// Load debug helpers
if (!function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

use FleekDash\Services\AnalyticsCacheService;
use FleekDash\Services\AnalyticsTracking\TrackingHelpers;
use FleekDash\Services\AnalyticsTracking\GeoIPProcessor;
use FleekDash\Services\AnalyticsTracking\UserAgentParser;
use FleekDash\Services\AnalyticsTracking\TrackingScriptGenerator;
use FleekDash\Services\AnalyticsTracking\SessionManager;
use FleekDash\Services\AnalyticsTracking\TrackingRequestRuntime;

/**
 * @since 2.2.0 Refactored - Uses TrackingScriptGenerator and SessionManager services
 */
class AnalyticsTrackingService
{
    private const SQL_SHOW_TABLES_LIKE = 'SHOW TABLES LIKE %s';

    private static $instance = null;
    private $wpdb;
    private $tablePageviews;
    private $tableSessions;
    private $tableDaily;
    private $cacheService;
    private $scriptGenerator;
    private $sessionManager;

    public function __construct()
    {
        // Always initialize properties (singleton pattern fix)
        global $wpdb;
        $this->wpdb = $wpdb;
        $this->tablePageviews = $wpdb->prefix . 'fleekdash_pageviews';
        $this->tableSessions = $wpdb->prefix . 'fleekdash_sessions';
        $this->tableDaily = $wpdb->prefix . 'fleekdash_analytics_daily';

        // Safety: ensure analytics tables exist (graceful, idempotent)
        $this->ensureTablesExist();

        // Initialize cache service for real-time invalidation
        $this->cacheService = new AnalyticsCacheService();

        // Initialize new services
        $this->scriptGenerator = new TrackingScriptGenerator();
        $this->sessionManager = new SessionManager();

        // Determine if analytics should be active
        $should_enable = true;
        try {
            if (class_exists('FleekDash\\Core\\IntegrationManager')) {
                $manager = \FleekDash\Core\IntegrationManager::getInstance();
                if (!$manager->isActive('analytics')) {
                    $should_enable = false;
                }
            }
            // Respect integration settings toggle
            $settings = \get_option('fleekdash_integration_analytics', []);
            if (isset($settings['enabled']) && !$settings['enabled']) {
                $should_enable = false;
            }
        } catch (\Throwable $e) {
            // On error, disable to be safe
            $should_enable = false;
        }

        // Only register hooks once and only if enabled
        if (self::$instance === null) {
            self::$instance = $this;

            if ($should_enable) {
                // Register AJAX handlers
                \add_action('wp_ajax_fleekdash_track_pageview', [$this, 'trackPageview']);
                \add_action('wp_ajax_nopriv_fleekdash_track_pageview', [$this, 'trackPageview']);

                // Auto-inject tracking script (only on frontend to prevent duplication)
                \add_action('wp_footer', [$this, 'injectTrackingScript']);
                // Removed admin_footer to prevent duplicate script injection

                // Track user registrations
                \add_action('user_register', [$this, 'trackUserRegistration']);

                // Daily aggregation cron
                \add_action('fleekdash_daily_analytics_aggregation', [$this, 'aggregateDailyData']);
                if (!wp_next_scheduled('fleekdash_daily_analytics_aggregation')) {
                    \wp_schedule_event(time(), 'daily', 'fleekdash_daily_analytics_aggregation');
                }
            }
        }
    }

    /**
     * Get singleton instance
     */
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Inject tracking script into frontend
     *
     * @since 2.2.0 Refactored - Uses TrackingScriptGenerator service
     */
    public function injectTrackingScript()
    {
        // Load settings
        $settings = \get_option('fleekdash_integration_analytics', []);

        // Check if tracking should be enabled
        if (!$this->scriptGenerator->shouldEnableTracking($settings)) {
            return;
        }

        // Prevent duplicate injection
        static $script_injected = false;
        if ($script_injected) {
            return;
        }
        $script_injected = true;

        // Get session ID
        $session_id = $this->sessionManager->getOrCreateSessionId();

        // Generate and output script
        echo $this->scriptGenerator->generateTrackingScript($session_id, $settings);
    }

    /**
     * Handle pageview tracking via AJAX
     */
    public function trackPageview()
    {
        $nonce = isset($_POST['nonce']) ? (string) $_POST['nonce'] : '';
        if (!\wp_verify_nonce($nonce, 'fleekdash_analytics')) {
            wp_die('Security check failed');
        }

        $settings = \get_option('fleekdash_integration_analytics', []);
        $trackingRules = TrackingRequestRuntime::buildTrackingRules($settings);
        if (TrackingRequestRuntime::shouldSkipTracking($trackingRules)) {
            wp_die('OK');
        }

        $session_id = \sanitize_text_field($_POST['session_id']);
        $page_url = esc_url_raw($_POST['page_url']);
        $page_title = \sanitize_text_field($_POST['page_title'] ?? '');
        $referrer = esc_url_raw($_POST['referrer'] ?? '');
        $user_agent = \sanitize_text_field($_POST['user_agent'] ?? '');
        $time_on_page = intval($_POST['time_on_page'] ?? 0);
        $is_exit = isset($_POST['is_exit']);
        $is_heartbeat = isset($_POST['is_heartbeat']);

        $user_id = \get_current_user_id();
        $ip_address = TrackingHelpers::getClientIP();
        $ip_address = TrackingRequestRuntime::anonymizeIpAddress($ip_address, $trackingRules['anonymizeIp']);
        $geo_data = GeoIPProcessor::getGeoData($ip_address);
        $device_data = UserAgentParser::parse($user_agent);

        // Get post data if available
        $post_data = TrackingHelpers::getPostDataFromUrl($page_url);

        if ($is_heartbeat || $is_exit) {
            $this->updateHeartbeatOrExitPageview($session_id, $page_url, $time_on_page);
            $this->sessionManager->updateSession($session_id, $page_url, $time_on_page);
        } else {
            $this->insertNewPageview(
                [
                    'userId' => $user_id,
                    'sessionId' => $session_id,
                    'pageUrl' => $page_url,
                    'pageTitle' => $page_title,
                    'postData' => $post_data,
                    'referrer' => $referrer,
                    'userAgent' => $user_agent,
                    'ipAddress' => $ip_address,
                    'geoData' => $geo_data,
                    'deviceData' => $device_data,
                ],
            );
            $this->sessionManager->createOrUpdateSession(
                $session_id,
                $page_url,
                $referrer,
                $user_id,
                $ip_address,
                $geo_data,
                $device_data,
            );

            // 🚀 INVALIDATE CACHE IMMEDIATELY for real-time updates
            $this->invalidateAnalyticsCache();
        }

        // For heartbeat/exit events, also invalidate cache to update time on page
        if ($is_heartbeat || $is_exit) {
            $this->invalidateAnalyticsCache();
        }

        wp_die('OK');
    }

    /**
     * Invalidate analytics cache for real-time updates
     */
    private function invalidateAnalyticsCache()
    {
        // Invalidate all analytics-related cache immediately
        $endpoints_to_invalidate = [
            'kpi_summary',
            'visitors',
            'pageviews',
            'popular_posts',
            'real_time'
        ];

        foreach ($endpoints_to_invalidate as $endpoint) {
            // Invalidate all variations (different time ranges and params)
            $this->cacheService->invalidate_endpoint_variations($endpoint);
        }

        // Log cache invalidation for debugging
        fleekdash_log_debug('🔄 FleekDash: Analytics cache invalidated for real-time updates');
    }

    /**
     * Track user registration
     */
    public function trackUserRegistration($user_id)
    {
        // This will be used by the analytics controller to get real user registration data
        \update_user_meta($user_id, 'fleekdash_registration_tracked', \current_time('mysql'));
    }

    /**
     * Aggregate daily analytics data
     */
    public function aggregateDailyData()
    {
        $yesterday = date('Y-m-d', strtotime('-1 day'));

        // Check if data already exists
        $existing = $this->wpdb->get_var(
            $this->wpdb->prepare("SELECT COUNT(*) FROM {$this->tableDaily} WHERE date = %s", $yesterday),
        );

        if ($existing > 0) {
            return; // Already processed
        }

        // Calculate metrics for yesterday
        $unique_visitors = $this->wpdb->get_var(
            $this->wpdb->prepare("
                SELECT COUNT(DISTINCT session_id)
                FROM {$this->tablePageviews}
                WHERE DATE(viewed_at) = %s
            ", $yesterday),
        );

        $total_pageviews = $this->wpdb->get_var(
            $this->wpdb->prepare("
                SELECT COUNT(*)
                FROM {$this->tablePageviews}
                WHERE DATE(viewed_at) = %s
            ", $yesterday),
        );

        $total_sessions = $this->wpdb->get_var(
            $this->wpdb->prepare("
                SELECT COUNT(*)
                FROM {$this->tableSessions}
                WHERE DATE(first_visit) = %s
            ", $yesterday),
        );

        $bounce_rate = $this->wpdb->get_var(
            $this->wpdb->prepare("
                SELECT ROUND(AVG(is_bounce) * 100, 2)
                FROM {$this->tableSessions}
                WHERE DATE(first_visit) = %s
            ", $yesterday),
        );

        $avg_session_duration = $this->wpdb->get_var(
            $this->wpdb->prepare("
                SELECT ROUND(AVG(session_duration))
                FROM {$this->tableSessions}
                WHERE DATE(first_visit) = %s AND session_duration > 0
            ", $yesterday),
        );

        // Insert aggregated data
        $this->wpdb->insert(
            $this->tableDaily,
            [
                'date' => $yesterday,
                'unique_visitors' => $unique_visitors ?: 0,
                'total_pageviews' => $total_pageviews ?: 0,
                'total_sessions' => $total_sessions ?: 0,
                'bounce_rate' => $bounce_rate ?: 0,
                'avg_session_duration' => $avg_session_duration ?: 0
            ],
        );
    }

    /**
     * Get real analytics data for controllers
     */
    public function getVisitorsData($start_date, $end_date, $aggregation = 'daily')
    {
        $results = [];
        $current = clone $start_date;
        $stepModifier = TrackingRequestRuntime::getAggregationStepModifier((string) $aggregation);

        while ($current <= $end_date) {
            $date_str = $current->format('Y-m-d');

            $dailyData = $this->getDailyAnalyticsRowByDate($date_str);
            $results[] = $dailyData
                ? $this->buildVisitorsRowFromDaily($date_str, $dailyData)
                : $this->buildVisitorsRowFromQueries($date_str);

            $current->modify($stepModifier);
        }

        return $results;
    }

    /**
     * Get real pageviews data
     */
    public function getPageviewsData($start_date, $end_date, $aggregation = 'daily')
    {
        $results = [];
        $current = clone $start_date;
        $stepModifier = TrackingRequestRuntime::getAggregationStepModifier((string) $aggregation);

        while ($current <= $end_date) {
            $date_str = $current->format('Y-m-d');

            $pageviews = $this->wpdb->get_var(
                $this->wpdb->prepare("
                    SELECT COUNT(*)
                    FROM {$this->tablePageviews}
                    WHERE DATE(viewed_at) = %s
                ", $date_str),
            );

            $results[] = [
                'date' => $date_str,
                'pageviews' => $pageviews ?: 0
            ];

            $current->modify($stepModifier);
        }

        return $results;
    }

    /**
     * Get real popular posts data
     */
    public function getPopularPostsData($start_date, $end_date, $limit = 10)
    {
        $results = $this->wpdb->get_results(
            $this->wpdb->prepare(
                "
                SELECT
                    p.post_id,
                    p.post_title,
                    COUNT(*) as view_count,
                    COUNT(DISTINCT p.session_id) as unique_views,
                    ROUND(AVG(p.time_on_page)) as avg_time_on_page,
                    ROUND(AVG(CASE WHEN p.time_on_page < 30 THEN 1 ELSE 0 END) * 100, 2) as bounce_rate
                FROM {$this->tablePageviews} p
                WHERE p.post_id IS NOT NULL
                AND DATE(p.viewed_at) BETWEEN %s AND %s
                GROUP BY p.post_id, p.post_title
                ORDER BY view_count DESC
                LIMIT %d
            ",
                $start_date->format('Y-m-d'),
                $end_date->format('Y-m-d'),
                $limit,
            ),
            ARRAY_A,
        );

        // Add post URLs
        foreach ($results as &$result) {
            $result['post_url'] = get_permalink($result['post_id']);
            $result['post_type'] = function_exists('get_post_type') ? \call_user_func('get_post_type', $result['post_id']) : null;
        }

        return $results;
    }

    /**
     * Install/upgrade analytics tables
     */
    public static function installTables()
    {
        // Include the migration file (returns anonymous class instance)
        $migration = require_once FLEEKDASH_DIR . '/database/Migrations/2025_01_08_000001_create_analytics_tables.php';

        if ($migration && method_exists($migration, 'up')) {
            $migration->up();
        }
    }

    /**
     * Ensure required analytics tables exist (called on construct)
     */
    private function ensureTablesExist(): void
    {
        try {
            // Use SHOW TABLES LIKE to check existence
            $pageviews_exists = $this->wpdb->get_var($this->wpdb->prepare(
                self::SQL_SHOW_TABLES_LIKE,
                $this->tablePageviews,
            ));
            $sessions_exists = $this->wpdb->get_var($this->wpdb->prepare(
                self::SQL_SHOW_TABLES_LIKE,
                $this->tableSessions,
            ));
            $daily_exists = $this->wpdb->get_var($this->wpdb->prepare(
                self::SQL_SHOW_TABLES_LIKE,
                $this->tableDaily,
            ));

            if ($pageviews_exists !== $this->tablePageviews || $sessions_exists !== $this->tableSessions || $daily_exists !== $this->tableDaily) {
                // Attempt to install tables (idempotent via dbDelta)
                self::installTables();
            }
        } catch (\Throwable $e) {
            fleekdash_log_error('FleekDash: ensureTablesExist failed: ' . $e->getMessage());
        }
    }


    private function updateHeartbeatOrExitPageview(string $sessionId, string $pageUrl, int $timeOnPage): void
    {
        $this->wpdb->update(
            $this->tablePageviews,
            [
                'time_on_page' => $timeOnPage,
                'is_bounce' => $timeOnPage < 30 ? 1 : 0,
            ],
            [
                'session_id' => $sessionId,
                'page_url' => $pageUrl,
            ],
            ['%d', '%d'],
            ['%s', '%s'],
        );
    }

    /** @param array<string, mixed> $payload */
    private function insertNewPageview(array $payload): void
    {
        $postData = \is_array($payload['postData'] ?? null) ? $payload['postData'] : [];
        $geoData = \is_array($payload['geoData'] ?? null) ? $payload['geoData'] : [];
        $deviceData = \is_array($payload['deviceData'] ?? null) ? $payload['deviceData'] : [];
        $this->wpdb->insert(
            $this->tablePageviews,
            [
                'user_id' => (int) ($payload['userId'] ?? 0) ?: null,
                'session_id' => (string) ($payload['sessionId'] ?? ''),
                'page_url' => (string) ($payload['pageUrl'] ?? ''),
                'page_title' => (string) ($payload['pageTitle'] ?? ''),
                'post_id' => $postData['post_id'] ?? null,
                'post_type' => $postData['post_type'] ?? '',
                'referrer' => (string) ($payload['referrer'] ?? ''),
                'user_agent' => (string) ($payload['userAgent'] ?? ''),
                'ip_address' => (string) ($payload['ipAddress'] ?? ''),
                'country_code' => $geoData['country_code'] ?? '',
                'country_name' => $geoData['country_name'] ?? '',
                'city' => $geoData['city'] ?? '',
                'device_type' => $deviceData['device_type'] ?? '',
                'browser' => $deviceData['browser'] ?? '',
                'os' => $deviceData['os'] ?? '',
                'viewed_at' => \current_time('mysql'),
            ],
        );
    }

    /** @return object|null */
    private function getDailyAnalyticsRowByDate(string $dateStr)
    {
        return $this->wpdb->get_row(
            $this->wpdb->prepare("SELECT * FROM {$this->tableDaily} WHERE date = %s", $dateStr),
        );
    }

    /**
     * @param object $dailyData
     * @return array<string, int|float|string>
     */
    private function buildVisitorsRowFromDaily(string $dateStr, $dailyData): array
    {
        return [
            'date' => $dateStr,
            'visitors' => (int) ($dailyData->unique_visitors ?? 0),
            'unique_visitors' => (int) ($dailyData->unique_visitors ?? 0),
            'total_pageviews' => (int) ($dailyData->total_pageviews ?? 0),
            'bounce_rate' => (float) ($dailyData->bounce_rate ?? 0),
            'avg_session_duration' => (int) ($dailyData->avg_session_duration ?? 0),
        ];
    }

    /** @return array<string, int|float|string> */
    private function buildVisitorsRowFromQueries(string $dateStr): array
    {
        $uniqueVisitors = $this->wpdb->get_var(
            $this->wpdb->prepare("
                SELECT COUNT(DISTINCT session_id)
                FROM {$this->tablePageviews}
                WHERE DATE(viewed_at) = %s
            ", $dateStr),
        );

        $totalPageviews = $this->wpdb->get_var(
            $this->wpdb->prepare("
                SELECT COUNT(*)
                FROM {$this->tablePageviews}
                WHERE DATE(viewed_at) = %s
            ", $dateStr),
        );

        $bounceRate = $this->wpdb->get_var(
            $this->wpdb->prepare("
                SELECT ROUND(AVG(is_bounce) * 100, 2)
                FROM {$this->tableSessions}
                WHERE DATE(first_visit) = %s
            ", $dateStr),
        );

        $avgSessionDuration = $this->wpdb->get_var(
            $this->wpdb->prepare("
                SELECT ROUND(AVG(session_duration), 0)
                FROM {$this->tableSessions}
                WHERE DATE(first_visit) = %s
                AND session_duration > 0
            ", $dateStr),
        );

        return [
            'date' => $dateStr,
            'visitors' => (int) ($uniqueVisitors ?: 0),
            'unique_visitors' => (int) ($uniqueVisitors ?: 0),
            'total_pageviews' => (int) ($totalPageviews ?: 0),
            'bounce_rate' => (float) ($bounceRate ?: 0),
            'avg_session_duration' => (int) ($avgSessionDuration ?: 0),
        ];
    }

}
