<?php

declare(strict_types=1);


/**
 * Core Web Vitals Service
 * 
 * Fetches real Core Web Vitals data from PageSpeed Insights API
 * 
 * @package ProRank\SEO\Core\Services
 */

namespace ProRank\SEO\Core\Services;

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




class CoreWebVitalsService {
    /**
     * In-request cache for PSI history table availability.
     *
     * @var bool|null
     */
    private static ?bool $history_table_ready = null;
    
    /**
     * API endpoint
     */
    const API_ENDPOINT = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed';
    
    /**
     * Get Core Web Vitals for a URL
     * 
     * @param string $url URL to analyze
     * @param string $strategy 'mobile' or 'desktop'
     * @return array|WP_Error
     */
    public function get_vitals($url = '', $strategy = 'mobile') {
        // Load PSI configuration
        require_once PRORANK_PLUGIN_DIR . 'includes/Config/pagespeed-config.php';
        
        // Get API key (will use default if not configured)
        $api_key = prorank_get_psi_api_key();
        
        // Use homepage if no URL provided
        if (empty($url)) {
            $url = home_url('/');
        }
        
        // Build API request URL
        $api_args = [
            'url' => $url,
            'strategy' => $strategy,
            'category' => 'performance',
        ];
        
        // Add API key if available
        if (!empty($api_key)) {
            $api_args['key'] = $api_key;
        }
        
        $api_url = add_query_arg($api_args, self::API_ENDPOINT);
        
        // Make API request with caching
        $cache_key = 'prorank_cwv_' . md5($url . '_' . $strategy);
        $cached = get_transient($cache_key);
        
        if (false !== $cached) {
            return $cached;
        }
        
        $response = wp_remote_get($api_url, [
            'timeout' => 30,
            'headers' => [
                'Referer' => home_url(),
            ],
        ]);
        
        if (is_wp_error($response)) {
            return $response;
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if (empty($data)) {
            return new \WP_Error('invalid_response', __('Invalid response from PageSpeed Insights API', 'prorank-seo'));
        }
        
        // Extract Core Web Vitals
        $result = $this->extract_vitals($data);
        
        // Cache for 1 hour
        set_transient($cache_key, $result, HOUR_IN_SECONDS);
        
        return $result;
    }
    
    /**
     * Extract Core Web Vitals from API response
     * 
     * @param array $data API response data
     * @return array
     */
    private function extract_vitals($data) {
        $result = [
            'field_data' => null,
            'lab_data' => null,
            'score' => 0,
            'audits' => [],
        ];
        
        // Get performance score
        if (isset($data['lighthouseResult']['categories']['performance']['score'])) {
            $result['score'] = round($data['lighthouseResult']['categories']['performance']['score'] * 100);
        }
        
        // Get field data (CrUX - real user data)
        if (isset($data['loadingExperience']['metrics'])) {
            $field_metrics = $data['loadingExperience']['metrics'];
            
            $result['field_data'] = [
                'lcp' => $this->extract_metric($field_metrics, 'LARGEST_CONTENTFUL_PAINT_MS'),
                'cls' => $this->extract_metric($field_metrics, 'CUMULATIVE_LAYOUT_SHIFT_SCORE'),
                'fcp' => $this->extract_metric($field_metrics, 'FIRST_CONTENTFUL_PAINT_MS'),
                'inp' => $this->extract_metric($field_metrics, 'INTERACTION_TO_NEXT_PAINT'),
                'ttfb' => $this->extract_metric($field_metrics, 'EXPERIMENTAL_TIME_TO_FIRST_BYTE'),
                'rtt' => $this->extract_metric($field_metrics, 'ROUND_TRIP_TIME'),
            ];
        }
        
        // Get lab data (Lighthouse synthetic data)
        if (isset($data['lighthouseResult']['audits'])) {
            $audits = $data['lighthouseResult']['audits'];
            
            $result['lab_data'] = [
                'lcp' => $this->extract_audit_value($audits, 'largest-contentful-paint'),
                'cls' => $this->extract_audit_value($audits, 'cumulative-layout-shift'),
                'tbt' => $this->extract_audit_value($audits, 'total-blocking-time'),
                'fcp' => $this->extract_audit_value($audits, 'first-contentful-paint'),
                'si' => $this->extract_audit_value($audits, 'speed-index'),
                'tti' => $this->extract_audit_value($audits, 'interactive'),
            ];
            
            // Extract key audits
            $audit_keys = [
                'largest-contentful-paint',
                'cumulative-layout-shift',
                'total-blocking-time',
                'first-contentful-paint',
                'speed-index',
                'interactive',
                'server-response-time',
                'render-blocking-resources',
                'uses-responsive-images',
                'offscreen-images',
                'unminified-css',
                'unminified-javascript',
                'unused-css-rules',
                'unused-javascript',
                'modern-image-formats',
                'uses-optimized-images',
                'uses-text-compression',
                'uses-rel-preconnect',
                'font-display',
            ];
            
            foreach ($audit_keys as $key) {
                if (isset($audits[$key])) {
                    $result['audits'][$key] = [
                        'score' => $audits[$key]['score'] ?? null,
                        'value' => $audits[$key]['numericValue'] ?? $audits[$key]['displayValue'] ?? null,
                        'title' => $audits[$key]['title'] ?? '',
                        'description' => $audits[$key]['description'] ?? '',
                    ];
                }
            }
        }
        
        return $result;
    }
    
    /**
     * Extract metric value from field data
     * 
     * @param array $metrics Field metrics
     * @param string $key Metric key
     * @return array|null
     */
    private function extract_metric($metrics, $key) {
        if (!isset($metrics[$key])) {
            return null;
        }
        
        $metric = $metrics[$key];
        
        return [
            'value' => $metric['percentile'] ?? null,
            'category' => $metric['category'] ?? 'AVERAGE',
            'distributions' => $metric['distributions'] ?? [],
        ];
    }
    
    /**
     * Extract audit value
     * 
     * @param array $audits Lighthouse audits
     * @param string $key Audit key
     * @return array|null
     */
    private function extract_audit_value($audits, $key) {
        if (!isset($audits[$key])) {
            return null;
        }
        
        $audit = $audits[$key];
        
        return [
            'value' => $audit['numericValue'] ?? null,
            'score' => $audit['score'] ?? null,
            'displayValue' => $audit['displayValue'] ?? '',
        ];
    }
    
    /**
     * Get multiple URLs vitals
     * 
     * @param array $urls URLs to analyze
     * @param string $strategy 'mobile' or 'desktop'
     * @return array
     */
    public function get_bulk_vitals($urls, $strategy = 'mobile') {
        $results = [];
        
        foreach ($urls as $url) {
            $vitals = $this->get_vitals($url, $strategy);
            
            if (!is_wp_error($vitals)) {
                $results[$url] = $vitals;
            }
        }
        
        return $results;
    }
    
    /**
     * Store vitals in database
     * 
     * @param string $url URL
     * @param string $strategy Strategy
     * @param array $vitals Vitals data
     * @return bool
     */
    public function store_vitals($url, $strategy, $vitals) {
        global $wpdb;
        
        $table_name = $wpdb->prefix . 'prorank_psi_history';
        if (!$this->ensure_history_table_exists($table_name)) {
            return false;
        }
        
        // Extract values for storage
        $lab_data = $vitals['lab_data'] ?? [];
        $field_data = $vitals['field_data'] ?? [];
        
        $data = [
            'url' => $url,
            'timestamp' => current_time('mysql'),
            'strategy' => $strategy,
            'performance_score' => $vitals['score'] ?? 0,
        ];
        
        // Lab data
        if (!empty($lab_data['lcp'])) {
            $data['lcp'] = $lab_data['lcp']['value'] ?? 0;
        }
        if (!empty($lab_data['cls'])) {
            $data['cls'] = $lab_data['cls']['value'] ?? 0;
        }
        if (!empty($lab_data['tbt'])) {
            $data['tbt'] = $lab_data['tbt']['value'] ?? 0;
        }
        if (!empty($lab_data['fcp'])) {
            $data['fcp'] = $lab_data['fcp']['value'] ?? 0;
        }
        if (!empty($lab_data['si'])) {
            $data['speed_index'] = $lab_data['si']['value'] ?? 0;
        }
        
        // Field data (if available, prefer over lab data)
        if (!empty($field_data['lcp'])) {
            $data['lcp'] = $field_data['lcp']['value'] ?? $data['lcp'] ?? 0;
        }
        if (!empty($field_data['cls'])) {
            $data['cls'] = $field_data['cls']['value'] ?? $data['cls'] ?? 0;
        }
        if (!empty($field_data['inp'])) {
            $data['inp'] = $field_data['inp']['value'] ?? 0;
        }
        if (!empty($field_data['ttfb'])) {
            $data['ttfb'] = $field_data['ttfb']['value'] ?? 0;
        }
        
        // Insert into database
        $result = $wpdb->insert($table_name, $data);
        
        return false !== $result;
    }

    /**
     * Ensure the PSI history table exists before writing.
     *
     * @param string $table_name Fully qualified table name.
     * @return bool
     */
    private function ensure_history_table_exists(string $table_name): bool {
        global $wpdb;

        if (self::$history_table_ready === true) {
            return true;
        }

        $existing = $wpdb->get_var(
            $wpdb->prepare('SHOW TABLES LIKE %s', $table_name)
        );

        if ($existing === $table_name) {
            self::$history_table_ready = true;
            return true;
        }

        $charset_collate = $wpdb->get_charset_collate();
        $sql = "CREATE TABLE IF NOT EXISTS {$table_name} (
            id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
            url varchar(255) NOT NULL,
            timestamp datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            strategy varchar(10) NOT NULL DEFAULT 'mobile',
            lcp decimal(10,2) DEFAULT NULL,
            inp decimal(10,2) DEFAULT NULL,
            cls decimal(10,4) DEFAULT NULL,
            tbt decimal(10,2) DEFAULT NULL,
            fcp decimal(10,2) DEFAULT NULL,
            ttfb decimal(10,2) DEFAULT NULL,
            speed_index decimal(10,2) DEFAULT NULL,
            performance_score int(3) DEFAULT NULL,
            error_message text DEFAULT NULL,
            PRIMARY KEY (id),
            KEY url (url),
            KEY timestamp (timestamp),
            KEY strategy (strategy),
            KEY url_strategy_timestamp (url, strategy, timestamp)
        ) {$charset_collate};";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta($sql);

        $existing = $wpdb->get_var(
            $wpdb->prepare('SHOW TABLES LIKE %s', $table_name)
        );

        self::$history_table_ready = ($existing === $table_name);

        if (!self::$history_table_ready && defined('WP_DEBUG') && WP_DEBUG) {
            prorank_log('ProRank SEO: Failed to ensure table exists: ' . $table_name);
        }

        return self::$history_table_ready;
    }
}
