<?php
/**
 * PageSpeed Insights API integration and data collection
 *
 * @package ContentPerformanceAnalyzer
 * @since 1.0.0
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

class CPAP_PageSpeed_Collector {
    
    private $api_key;
    private $strategy;
    private $rate_limit;
    private $last_request_time = 0;
    private $categories;
    private $cache_hours;

    /**
     * Helper to retrieve sanitized URLs table name.
     *
     * @return string
     */
    private function get_urls_table_name() {
        global $wpdb;
        return $wpdb->prefix . 'cpanalyzer_urls';
    }

    private function get_sanitized_urls_table_name() {
        return esc_sql( $this->get_urls_table_name() );
    }
    
    /**
     * Constructor - Initialize with settings
     */
    public function __construct() {
        $this->api_key = get_option('cpanalyzer_pagespeed_api_key', '');
        $this->strategy = get_option('cpanalyzer_pagespeed_strategy', 'mobile');
        $this->rate_limit = (int) get_option('cpanalyzer_pagespeed_rate_limit', 30);
        $this->categories = get_option('cpanalyzer_pagespeed_categories', ['PERFORMANCE']);
        $this->cache_hours = (int) get_option('cpanalyzer_pagespeed_cache_hours', 24);
    }
    
    /**
     * Check if PSI is enabled. An API key is no longer required — without
     * one, requests go through the hosted PageSpeed service, which holds
     * its own key server-side.
     */
    public function is_enabled() {
        $enabled = get_option('cpanalyzer_pagespeed_enable', 'no');
        return ($enabled === 'yes' || $enabled === true);
    }
    
    /**
     * Validate API key by making a test request
     */
    public function validate_api_key($api_key = null) {
        $test_key = $api_key ?? $this->api_key;
        
        if (empty($test_key)) {
            return array('valid' => false, 'message' => __('API key is required', 'content-performance-analyzer'));
        }
        
        // Test with a simple request to Google's homepage
        $test_url = 'https://www.google.com';
        $api_url = add_query_arg(array(
            'url' => $test_url,
            'key' => $test_key,
            'strategy' => 'mobile',
            'category' => 'PERFORMANCE'
        ), 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed');
        
        $response = wp_remote_get($api_url, array(
            'timeout' => 15,
            'sslverify' => get_option('cpanalyzer_verify_ssl', 'yes') !== 'no'
        ));
        
        if (is_wp_error($response)) {
            return array(
                'valid' => false,
                'message' => sprintf(
                    /* translators: %s: WordPress HTTP API error message */
                    __('Network error: %s', 'content-performance-analyzer'),
                    $response->get_error_message()
                )
            );
        }
        
        $response_code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        
        if ($response_code === 200) {
            $data = json_decode($body, true);
            if (isset($data['lighthouseResult'])) {
                return array('valid' => true, 'message' => __('API key is valid', 'content-performance-analyzer'));
            }
        } elseif ($response_code === 400) {
            $error_data = json_decode($body, true);
            $error_msg = isset($error_data['error']['message']) ? $error_data['error']['message'] : __('Invalid API key', 'content-performance-analyzer');
            return array('valid' => false, 'message' => $error_msg);
        }
        
        return array('valid' => false, 'message' => __('API validation failed', 'content-performance-analyzer'));
    }
    
    /**
     * Collect PageSpeed data for a single URL
     */
    public function collect_pagespeed_data($url, $strategy_override = null) {
		// FIX: Use production URL for PSI instead of staging
		$_gsc = get_option('cpanalyzer_site_url', '');
		$_prod = ( strpos( $_gsc, 'sc-domain:' ) === 0 ) ? 'https://' . str_replace( 'sc-domain:', '', $_gsc ) : get_site_url();
		$_staging = rtrim( get_site_url(), '/' );
		$_prod    = rtrim( $_prod, '/' );
		if ( strpos( $url, 'http' ) !== 0 ) { $url = $_prod . '/' . ltrim( $url, '/' ); }
		elseif ( $_staging !== $_prod ) { $url = str_replace( $_staging, $_prod, $url ); }
		// END FIX

        if (!$this->is_enabled()) {
            return false;
        }
        
        $strategy = $strategy_override ?? $this->strategy;
        
        // Handle 'both' strategy with dual calls
        if ($strategy === 'both') {
            return $this->collect_dual_strategy_data($url);
        }
        
        // Check cache first
        if ($cached_data = $this->get_cached_psi_data($url, $strategy)) {
            return $cached_data;
        }
        
        // Enforce rate limiting
        $this->enforce_rate_limit();
        
        // Make PSI API call
        $psi_data = $this->call_psi_api($url, $strategy);
        
        // Cache the result if successful
        if ($psi_data && !isset($psi_data['error'])) {
            $this->cache_psi_data($url, $strategy, $psi_data);
            
            // Wrap in strategy structure for consistency with dual strategy format
            return array(
                $strategy => $psi_data,
                'primary_strategy' => $strategy
            );
        }
        
        return $psi_data;
    }
    
    /**
     * Collect data for both mobile and desktop strategies
     */
    private function collect_dual_strategy_data($url) {
        $results = array();
        
        // Mobile first (primary strategy)
        $mobile_data = $this->call_psi_api($url, 'mobile');
        if ($mobile_data && !isset($mobile_data['error'])) {
            $results['mobile'] = $mobile_data;
        }
        
        // Desktop second
        $this->enforce_rate_limit(); // Additional delay between calls
        $desktop_data = $this->call_psi_api($url, 'desktop');
        if ($desktop_data && !isset($desktop_data['error'])) {
            $results['desktop'] = $desktop_data;
        }
        
        if (empty($results)) {
            return false;
        }
        
        // Set primary strategy (mobile preferred)
        $results['primary_strategy'] = isset($results['mobile']) ? 'mobile' : 'desktop';
        
        return $results;
    }
    
    /**
     * Batch collect PSI data for multiple URLs
     */
    public function batch_collect($urls) {
        if (!$this->is_enabled() || empty($urls)) {
            return;
        }
        
        $processed_count = 0;
        $success_count = 0;
        $start_time = microtime(true);
        
        foreach ($urls as $url) {
            // Check execution time budget
            $elapsed_time = microtime(true) - $start_time;
            if ($elapsed_time > 60 && $processed_count > 0) { // Stop if over 1 minute
                $this->log_event('batch_timeout', sprintf('PSI batch halted after %d URLs - time budget exceeded', $processed_count));
                break;
            }
            
            $processed_count++;
            
            try {
                $psi_data = $this->collect_pagespeed_data($url);
                
                if ($psi_data && !isset($psi_data['error'])) {
                    // Store PSI data in existing content_data structure
                    $this->store_psi_data($url, $psi_data);
                    $success_count++;
                    
                    $this->log_event('psi_success', sprintf('PSI data collected for %s', $url));
                } else {
                    $error_msg = isset($psi_data['error']) ? $psi_data['error'] : 'Unknown PSI error';
                    $this->log_event('psi_error', sprintf('PSI failed for %s: %s', $url, $error_msg));
                    
                    // Handle quota errors by stopping batch
                    if (strpos($error_msg, '429') !== false || strpos($error_msg, 'quota') !== false) {
                        $this->log_event('quota_exceeded', 'PSI quota hit - stopping batch processing');
                        break;
                    }
                }
                
            } catch (Exception $e) {
                $this->log_event('psi_exception', sprintf('PSI exception for %s: %s', $url, $e->getMessage()));
            }
        }
        
        $this->log_event('batch_complete', sprintf('PSI batch complete: %d/%d URLs processed successfully', $success_count, $processed_count));
    }
    
    /**
     * Make PSI API call for single URL and strategy
     */
    private function call_psi_api($url, $strategy) {
        // No own API key configured → use the hosted PageSpeed service.
        if (empty($this->api_key)) {
            return $this->call_hosted_psi_api($url, $strategy);
        }

        // Build query parameters - use only PERFORMANCE category for reliability
        // PSI API can be finicky with multiple categories, and we only need performance data
        $query_params = array(
            'url' => $url,
            'key' => $this->api_key,
            'strategy' => $strategy,
            'category' => 'PERFORMANCE'  // Always use PERFORMANCE for Core Web Vitals and scores
        );
        
        $api_url = add_query_arg($query_params, 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed');

        // Log the request without the API key
        $this->log_event('debug', 'PSI request: ' . $url . ' (' . $strategy . ')');
        
        $response = wp_remote_get($api_url, array(
            'timeout' => 60, // Extended timeout for slow staging URLs
            'sslverify' => get_option('cpanalyzer_verify_ssl', 'yes') !== 'no'
        ));
        
        if (is_wp_error($response)) {
            return array(
                'error' => sprintf(
                    /* translators: %s: WordPress HTTP API error message */
                    __('Network error: %s', 'content-performance-analyzer'),
                    $response->get_error_message()
                )
            );
        }
        
        $response_code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        
        // Handle various response codes
        $error_result = $this->handle_api_error($response_code, $body);
        if ($error_result) {
            return $error_result;
        }
        
        $data = json_decode($body, true);
        if (!$data || !isset($data['lighthouseResult'])) {
            return array('error' => __('Invalid PSI response format', 'content-performance-analyzer'));
        }
        
        // Normalize and return the response
        return $this->normalize_psi_response($data, $strategy);
    }
    
    /**
     * Fetch PageSpeed data through the hosted service — no API key needed
     * on the site. Auth is this installation's bearer token; the Google
     * key lives only on the server.
     *
     * @param  string $url      Full URL to analyze.
     * @param  string $strategy 'mobile' or 'desktop'.
     * @return array Same shape as normalize_psi_response(), or ['error' => ...].
     */
    private function call_hosted_psi_api($url, $strategy) {
        if (!class_exists('CPAP_Google_OAuth')) {
            return array('error' => __('Hosted PageSpeed service unavailable.', 'content-performance-analyzer'));
        }

        $oauth = new CPAP_Google_OAuth();
        $token = $oauth->get_installation_token();

        if ('' === $token) {
            return array('error' => __('Could not reach the hosted PageSpeed service. Add your own PSI API key in Settings, or try again later.', 'content-performance-analyzer'));
        }

        $this->log_event('debug', 'Hosted PSI request: ' . $url . ' (' . $strategy . ')');

        $response = wp_remote_post(
            $oauth->get_proxy_base() . '/api/v1/pagespeed',
            array(
                'timeout' => 90,
                'headers' => array(
                    'Content-Type'  => 'application/json',
                    'Authorization' => 'Bearer ' . $token,
                ),
                'body'    => wp_json_encode(array('url' => $url, 'strategy' => $strategy)),
            )
        );

        if (is_wp_error($response)) {
            return array(
                'error' => sprintf(
                    /* translators: %s: WordPress HTTP API error message */
                    __('Network error: %s', 'content-performance-analyzer'),
                    $response->get_error_message()
                ),
            );
        }

        $code = (int) wp_remote_retrieve_response_code($response);
        $body = json_decode(wp_remote_retrieve_body($response), true);

        if (401 === $code) {
            // Token revoked or lost server-side — re-register on next run.
            $oauth->reset_installation_token();
            return array('error' => __('Hosted PageSpeed token was rejected. It will re-register automatically on the next scan.', 'content-performance-analyzer'));
        }

        if (200 !== $code || !is_array($body)) {
            $message = is_array($body) && !empty($body['error_description'])
                ? sanitize_text_field($body['error_description'])
                : sprintf(
                    /* translators: %d: HTTP status code */
                    __('Hosted PageSpeed error (HTTP %d).', 'content-performance-analyzer'),
                    $code
                );
            return array('error' => $message);
        }

        if (empty($body['results'][0]) || !is_array($body['results'][0])) {
            $message = !empty($body['errors'][0]['message'])
                ? sanitize_text_field($body['errors'][0]['message'])
                : __('PageSpeed request failed.', 'content-performance-analyzer');
            return array('error' => $message);
        }

        return $this->normalize_hosted_psi_result($body['results'][0]);
    }

    /**
     * Map the hosted service's normalized response onto the exact shape
     * normalize_psi_response() produces, so storage and display code is
     * identical for both paths.
     *
     * @param  array $result One entry from the service's results array.
     * @return array
     */
    private function normalize_hosted_psi_result($result) {
        $lab      = isset($result['labMetrics']) && is_array($result['labMetrics']) ? $result['labMetrics'] : array();
        $metrics  = array();
        $cwv_pass = true;

        if (isset($lab['LCP_ms'])) {
            $metrics['LCP_ms'] = (int) $lab['LCP_ms'];
            if ($metrics['LCP_ms'] > 2500) {
                $cwv_pass = false;
            }
        }
        if (isset($lab['INP_ms'])) {
            $metrics['INP_ms'] = (int) $lab['INP_ms'];
            if ($metrics['INP_ms'] > 200) {
                $cwv_pass = false;
            }
        }
        if (isset($lab['CLS'])) {
            $metrics['CLS'] = round((float) $lab['CLS'], 3);
            if ($metrics['CLS'] > 0.1) {
                $cwv_pass = false;
            }
        }
        foreach (array('FCP_ms', 'TBT_ms', 'SI_ms', 'TTFB_ms') as $metric_key) {
            if (isset($lab[$metric_key])) {
                $metrics[$metric_key] = (int) $lab[$metric_key];
            }
        }

        $opportunities = array();
        foreach ((array) ($result['opportunities'] ?? array()) as $opportunity) {
            if (!empty($opportunity['id'])) {
                $opportunities[] = array(
                    'id'    => sanitize_key($opportunity['id']),
                    'value' => (int) ($opportunity['savingsMs'] ?? 0),
                );
            }
        }

        return array(
            'score'                => isset($result['scores']['performance']) ? (int) $result['scores']['performance'] : null,
            'metrics'              => $metrics,
            'core_web_vitals_pass' => $cwv_pass,
            'opportunities'        => $opportunities,
            'retrieved_at'         => current_time('mysql'),
        );
    }

    /**
     * Handle API errors with appropriate responses
     */
    private function handle_api_error($response_code, $response_body) {
        switch ($response_code) {
            case 200:
                return null; // Success - continue processing
                
            case 400:
                $error_data = json_decode($response_body, true);
                $error_msg = isset($error_data['error']['message']) ? $error_data['error']['message'] : __('Bad request', 'content-performance-analyzer');
                return array(
                    'error' => sprintf(
                        /* translators: %s: PSI API error message */
                        __('API error 400: %s', 'content-performance-analyzer'),
                        $error_msg
                    )
                );
                
            case 429:
                return array('error' => __('Rate limit exceeded (429)', 'content-performance-analyzer'));
                
            case 500:
            case 502:
            case 503:
                // Server errors - could retry but skip for now
                return array(
                    'error' => sprintf(
                        /* translators: %d: PSI HTTP status code */
                        __('PSI server error (%d)', 'content-performance-analyzer'),
                        $response_code
                    )
                );
                
            default:
                return array(
                    'error' => sprintf(
                        /* translators: %d: PSI HTTP status code */
                        __('Unexpected response code: %d', 'content-performance-analyzer'),
                        $response_code
                    )
                );
        }
    }
    
    /**
     * Normalize PSI API response to standardized format
     */
    private function normalize_psi_response($response, $strategy) {
        $lighthouse = $response['lighthouseResult'];
        $audits = $lighthouse['audits'] ?? array();
        
        // Extract performance score
        $categories = $lighthouse['categories'] ?? array();
        $performance_score = isset($categories['performance']['score']) 
            ? round($categories['performance']['score'] * 100) 
            : null;
        
        // Extract Core Web Vitals metrics
        $metrics = array();
        $cwv_pass = true;
        
        // Largest Contentful Paint (LCP)
        if (isset($audits['largest-contentful-paint']['numericValue'])) {
            $lcp_ms = round($audits['largest-contentful-paint']['numericValue']);
            $metrics['LCP_ms'] = $lcp_ms;
            if ($lcp_ms > 2500) $cwv_pass = false;
        }
        
        // Interaction to Next Paint (INP) - may not be available in all audits
        if (isset($audits['experimental-interaction-to-next-paint']['numericValue'])) {
            $inp_ms = round($audits['experimental-interaction-to-next-paint']['numericValue']);
            $metrics['INP_ms'] = $inp_ms;
            if ($inp_ms > 200) $cwv_pass = false;
        } elseif (isset($audits['max-potential-fid']['numericValue'])) {
            // Fallback to FID if INP not available
            $metrics['INP_ms'] = round($audits['max-potential-fid']['numericValue']);
        }
        
        // Cumulative Layout Shift (CLS)
        if (isset($audits['cumulative-layout-shift']['numericValue'])) {
            $cls = round($audits['cumulative-layout-shift']['numericValue'], 3);
            $metrics['CLS'] = $cls;
            if ($cls > 0.1) $cwv_pass = false;
        }
        
        // Additional useful metrics
        if (isset($audits['first-contentful-paint']['numericValue'])) {
            $metrics['FCP_ms'] = round($audits['first-contentful-paint']['numericValue']);
        }
        
        if (isset($audits['total-blocking-time']['numericValue'])) {
            $metrics['TBT_ms'] = round($audits['total-blocking-time']['numericValue']);
        }
        
        if (isset($audits['speed-index']['numericValue'])) {
            $metrics['SI_ms'] = round($audits['speed-index']['numericValue']);
        }
        
        // Extract top opportunities (limit to 3 most impactful)
        $opportunities = array();
        $opportunity_audits = array(
            'unused-css-rules', 'render-blocking-resources', 'unused-javascript',
            'optimize-images', 'minify-css', 'minify-javascript', 'efficient-animated-content'
        );
        
        foreach ($opportunity_audits as $audit_id) {
            if (isset($audits[$audit_id]) && 
                isset($audits[$audit_id]['details']['overallSavingsMs']) &&
                $audits[$audit_id]['details']['overallSavingsMs'] > 100) {
                
                $opportunities[] = array(
                    'id' => $audit_id,
                    'value' => round($audits[$audit_id]['details']['overallSavingsMs'])
                );
                
                if (count($opportunities) >= 3) break;
            }
        }
        
        // Sort opportunities by impact
        usort($opportunities, function($a, $b) {
            return $b['value'] - $a['value'];
        });
        
        return array(
            'score' => $performance_score,
            'metrics' => $metrics,
            'core_web_vitals_pass' => $cwv_pass,
            'opportunities' => $opportunities,
            'retrieved_at' => current_time('mysql')
        );
    }
    
    /**
     * Store PSI data in the existing content_data structure
     */
    private function store_psi_data($url, $psi_data) {
        global $wpdb;
        $cpanalyzer_urls_table = $this->get_urls_table_name();

        // Get existing content_data
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQLPlaceholders.UnsupportedIdentifierPlaceholder -- Custom table queries with %i placeholder (requires WP 6.2+, our minimum version)
        $existing_content = $wpdb->get_var($wpdb->prepare(
            "SELECT content_data FROM %i WHERE url = %s",
            $cpanalyzer_urls_table,
            $url
        ));

        $content_data = $existing_content ? json_decode($existing_content, true) : array();

        // Add PSI data to content structure
        if (!isset($content_data['psi'])) {
            $content_data['psi'] = array();
        }

        // Handle single strategy vs both strategies - normalize to consistent format
        if (isset($psi_data['primary_strategy'])) {
            // Both strategies result - already normalized
            $content_data['psi'] = $psi_data;
        } else {
            // Single strategy result - normalize to standard format
            $strategy = $this->strategy === 'both' ? 'mobile' : $this->strategy;
            $content_data['psi'] = array(
                $strategy => $psi_data,
                'primary_strategy' => $strategy
            );
        }

        // Update or insert the record
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQLPlaceholders.UnsupportedIdentifierPlaceholder -- Custom table queries with %i placeholder (requires WP 6.2+, our minimum version)
        $existing_record = $wpdb->get_var($wpdb->prepare(
            "SELECT id FROM %i WHERE url = %s",
            $cpanalyzer_urls_table,
            $url
        ));
        
        if ($existing_record) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- PSI data updates to custom table
            $wpdb->update(
                $cpanalyzer_urls_table,
                array('content_data' => wp_json_encode($content_data)),
                array('url' => $url)
            );
        } else {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- PSI data inserts to custom table
            $wpdb->insert(
                $cpanalyzer_urls_table,
                array(
                    'url' => $url,
                    'content_data' => wp_json_encode($content_data),
                    'status' => 'success',
                    'last_scanned' => current_time('mysql')
                )
            );
        }
        
        // Also update the insights display data (WordPress options)
        $this->update_insights_psi_data($url, $content_data['psi']);
    }
    
    /**
     * Update PSI data in the insights display (WordPress options)
     */
    private function update_insights_psi_data($url, $psi_data) {
        $content_data_option = get_option('cpanalyzer_content_data', array());
        
        if (!isset($content_data_option[$url])) {
            $content_data_option[$url] = array();
        }
        
        $content_data_option[$url]['psi'] = $psi_data;
        update_option('cpanalyzer_content_data', $content_data_option, false);
    }
    
    /**
     * Get URLs that need PSI analysis based on flagged status and traffic
     */
    public function get_psi_target_urls($all_urls) {
        // An explicit page selection from Settings takes precedence, capped at
        // cpanalyzer_psi_page_limit() (15 free, 30 with Pro).
        $selected = array_values(array_filter(array_map('strval', (array) get_option('cpanalyzer_psi_pages', array()))));
        if (!empty($selected)) {
            $selected = array_slice($selected, 0, cpanalyzer_psi_page_limit());
            $matched  = array_values(array_intersect($selected, (array) $all_urls));
            return !empty($matched) ? $matched : $selected;
        }

        // Get flagged URLs (high priority)
        $flagged_urls = array_keys((array) get_option('cpanalyzer_page_flags', array()));
        
        // Get high-traffic unflagged URLs for performance discovery
        $top_traffic_urls = $this->get_top_traffic_unflagged($all_urls, 20);
        
        // Get URLs with stale PSI data
        $stale_psi_urls = $this->get_urls_with_stale_psi($all_urls);
        
        // Combine and deduplicate
        return array_unique(array_merge($flagged_urls, $top_traffic_urls, $stale_psi_urls));
    }
    
    /**
     * Get top traffic unflagged URLs for performance discovery
     */
    private function get_top_traffic_unflagged($urls, $limit = 20) {
        $ga_data = get_option('cpanalyzer_ga_rows', array());
        $flagged_urls = array_keys((array) get_option('cpanalyzer_page_flags', array()));
        
        $unflagged_with_traffic = array();
        
        foreach ($urls as $url) {
            if (!in_array($url, $flagged_urls) && isset($ga_data[$url])) {
                $views = $ga_data[$url]['views'] ?? 0;
                if ($views > 100) { // Minimum traffic threshold
                    $unflagged_with_traffic[$url] = $views;
                }
            }
        }
        
        // Sort by traffic descending
        arsort($unflagged_with_traffic);
        
        return array_slice(array_keys($unflagged_with_traffic), 0, $limit);
    }
    
    /**
     * Get URLs with stale PSI data (older than cache_hours)
     */
    private function get_urls_with_stale_psi($urls) {
        $content_data = get_option('cpanalyzer_content_data', array());
        $stale_threshold = time() - ($this->cache_hours * 3600);
        $stale_urls = array();
        
        foreach ($urls as $url) {
            if (isset($content_data[$url]['psi'])) {
                $psi_data = $content_data[$url]['psi'];
                
                // Check both mobile and desktop timestamps if available
                $strategies = array('mobile', 'desktop');
                $is_stale = true;
                
                foreach ($strategies as $strategy) {
                    if (isset($psi_data[$strategy]['retrieved_at'])) {
                        $retrieved_time = strtotime($psi_data[$strategy]['retrieved_at']);
                        if ($retrieved_time > $stale_threshold) {
                            $is_stale = false;
                            break;
                        }
                    }
                }
                
                if ($is_stale) {
                    $stale_urls[] = $url;
                }
            } else {
                // No PSI data at all - needs analysis
                $stale_urls[] = $url;
            }
        }
        
        return $stale_urls;
    }
    
    /**
     * Check if URL has PSI data and determine if performance should be flagged
     */
    public function should_flag_performance($url) {
        $content_data = get_option('cpanalyzer_content_data', array());
        
        if (!isset($content_data[$url]['psi'])) {
            return false; // No PSI data available
        }
        
        $psi_data = $content_data[$url]['psi'];
        $primary_strategy = $psi_data['primary_strategy'] ?? 'mobile';
        $strategy_data = $psi_data[$primary_strategy] ?? null;
        
        if (!$strategy_data) {
            return false;
        }
        
        $score = $strategy_data['score'] ?? null;
        $cwv_pass = $strategy_data['core_web_vitals_pass'] ?? true;
        
        // Flag if fails Core Web Vitals OR score is below 50
        return !$cwv_pass || ($score !== null && $score < 50);
    }
    
    /**
     * Get cached PSI data if within cache period
     */
    private function get_cached_psi_data($url, $strategy) {
        $content_data = get_option('cpanalyzer_content_data', array());
        
        if (!isset($content_data[$url]['psi'][$strategy])) {
            return false;
        }
        
        $psi_data = $content_data[$url]['psi'][$strategy];
        
        if (!isset($psi_data['retrieved_at'])) {
            return false;
        }
        
        $retrieved_time = strtotime($psi_data['retrieved_at']);
        $cache_expiry = time() - ($this->cache_hours * 3600);
        
        return ($retrieved_time > $cache_expiry) ? $psi_data : false;
    }
    
    /**
     * Cache PSI data
     */
    private function cache_psi_data($url, $strategy, $psi_data) {
        // Caching is handled in store_psi_data method
        // This method exists for consistency with the planned architecture
    }
    
    /**
     * Enforce rate limiting between API calls
     */
    private function enforce_rate_limit() {
        $time_since_last = microtime(true) - $this->last_request_time;
        $min_interval = 60 / $this->rate_limit; // seconds per request
        
        if ($time_since_last < $min_interval) {
            $sleep_time = $min_interval - $time_since_last;
            usleep($sleep_time * 1000000); // Convert to microseconds
        }
        
        $this->last_request_time = microtime(true);
    }
    
    /**
     * Log events for debugging and monitoring
     */
    private function log_event($event_type, $message) {
        // Use existing logging system from CPA_Core if available
        $core = CPAP_Core::get_instance();
        if ($core && method_exists($core, 'log_event')) {
            $core->log_event('psi_' . $event_type, $message);
        } else {
            // Fallback to debug logging
            if (get_option('cpanalyzer_debug_mode', 'no') === 'yes' && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Protected debug logging
                error_log("[CPANALYZER PSI] $event_type: $message");
            }
        }
    }


}
