<?php

declare(strict_types=1);

namespace ProRank\SEO\Core\Performance;

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

/**
 * Read-only font-delivery diagnostic.
 *
 * VISIBILITY ONLY. This composes the EXISTING font subsystem — it reuses
 * FontOptimizationModule::get_stats() as the single source of truth for cache
 * counts and does NOT register hooks, rewrite output, change settings, clear
 * cached files, or apply preloads. The capped preload list is advisory.
 */
class FontDeliveryHealth {

    /** Max advisory preload suggestions (never auto-applied). */
    private const PRELOAD_SUGGEST_CAP = 2;

    /** Cap the diagnostic home fetch (head + early body is all we inspect). */
    private const MAX_HTML_BYTES = 768000;

    public function report(): array {
        $asset = get_option('prorank_asset_optimization_settings', []);
        $cache = get_option('prorank_cache_settings', []);
        if (!is_array($asset)) {
            $asset = [];
        }
        if (!is_array($cache)) {
            $cache = [];
        }

        $settings = [
            'host_google_fonts_locally' => !empty($asset['host_google_fonts_locally']),
            'font_display_swap'         => !empty($asset['font_display_swap']),
            'font_subsetting_enabled'   => !empty($asset['font_subsetting_enabled']),
            'smart_fonts_enabled'       => !empty($asset['smart_fonts_enabled']),
            'font_preload_enabled'      => !empty($cache['font_preload_enabled']),
            'font_preload_url_count'    => $this->count_preload_urls($cache['font_preload_urls'] ?? ''),
        ];

        // Single source of truth for cache stats: the existing module method.
        $stats = ['total_fonts' => 0, 'total_size' => 0, 'google_fonts_found' => 0];
        if (class_exists('\\ProRank\\SEO\\Modules\\Performance\\FontOptimizationModule')) {
            try {
                $module = new \ProRank\SEO\Modules\Performance\FontOptimizationModule();
                if (method_exists($module, 'get_stats')) {
                    $s = $module->get_stats();
                    if (is_array($s)) {
                        $stats = array_merge($stats, $s);
                    }
                }
            } catch (\Throwable $e) {
                // Stats are best-effort; never fatal.
            }
        }

        $rendered = $this->analyze_rendered_home();

        $flags = $this->evaluate_flags($settings, $stats, $rendered);

        $status = 'good';
        foreach ($flags as $f) {
            if (in_array($f['severity'], ['critical', 'high'], true)) {
                $status = 'critical';
                break;
            }
            if ($f['severity'] === 'medium') {
                $status = 'warning';
            }
        }

        return [
            'generated_at' => current_time('mysql'),
            'status'       => $status,
            'settings'     => $settings,
            'cache'        => [
                'cached_font_files' => (int) $stats['total_fonts'],
                'cached_bytes'      => (int) $stats['total_size'],
                'cached_human'      => size_format((int) $stats['total_size']),
                'google_fonts_found_by_scanner' => (int) $stats['google_fonts_found'],
            ],
            'rendered'     => $rendered,
            'flags'        => $flags,
        ];
    }

    private function count_preload_urls($raw): int {
        if (!is_string($raw) || trim($raw) === '') {
            return 0;
        }
        $lines = preg_split('/\r\n|\r|\n/', trim($raw)) ?: [];
        $lines = array_filter(array_map('trim', $lines), static fn($l) => $l !== '');
        return count($lines);
    }

    /**
     * Fetch the home page once (read-only) and inspect font delivery.
     *
     * @return array
     */
    private function analyze_rendered_home(): array {
        $result = [
            'fetched'                 => false,
            'external_google_fonts'   => false,
            'external_google_count'   => 0,
            'prorank_local_served'    => false,
            'self_hosted_owner'       => 'none',
            'font_display_swap_seen'  => 0,
            'preloaded_fonts'         => [],
            'preload_suggestions'     => [],
        ];

        $url = home_url('/');
        // Read-only diagnostic: do NOT bypass the cache (no Cache-Control:
        // no-cache — that would create cache-cold front-end hits), keep normal
        // TLS verification, short timeout, and cap the response so a large
        // page can't bloat an admin request. Font links/preloads/@font-face
        // we care about are in the <head>/early body, well within the cap.
        $response = wp_remote_get($url, [
            'timeout'             => 5,
            'redirection'         => 3,
            'limit_response_size' => self::MAX_HTML_BYTES,
            'headers'             => [
                'User-Agent' => 'ProRank-SEO/FontDeliveryHealth',
            ],
        ]);
        if (is_wp_error($response)) {
            return $result;
        }
        $html = (string) wp_remote_retrieve_body($response);
        if ($html === '') {
            return $result;
        }
        $result['fetched'] = true;

        // External Google Fonts still loading?
        $gf = preg_match_all('#fonts\.googleapis\.com|fonts\.gstatic\.com#i', $html);
        $result['external_google_count'] = $gf === false ? 0 : (int) $gf;
        $result['external_google_fonts'] = $result['external_google_count'] > 0;

        // ProRank's own local cache actually referenced on the page?
        $result['prorank_local_served'] = stripos($html, '/uploads/prorank-fonts') !== false;

        // Who self-hosts the fonts the page actually uses?
        $owner = 'none';
        if (preg_match('#/wp-content/fonts/#i', $html)) {
            // Elementor & some themes self-host Google fonts under wp-content/fonts.
            if (stripos($html, 'elementor') !== false) {
                $owner = 'elementor';
            } elseif (stripos($html, '/themes/neve') !== false || stripos($html, 'neve-') !== false) {
                $owner = 'neve-theme';
            } else {
                $owner = 'theme-or-other';
            }
        } elseif (preg_match('#woocommerce[^"\']*\.woff2?#i', $html)) {
            $owner = 'woocommerce';
        }
        $result['self_hosted_owner'] = $owner;

        // font-display:swap coverage (informational count).
        $fd = preg_match_all('#font-display\s*:\s*swap#i', $html);
        $result['font_display_swap_seen'] = $fd === false ? 0 : (int) $fd;

        // Currently preloaded font files.
        if (preg_match_all('#<link[^>]*rel=["\']preload["\'][^>]*as=["\']font["\'][^>]*>#i', $html, $links)) {
            foreach ($links[0] as $tag) {
                if (preg_match('#href=["\']([^"\']+)["\']#i', $tag, $m)) {
                    $result['preloaded_fonts'][] = $m[1];
                }
            }
        }

        // Advisory (capped) suggestions: woff2 the page uses that are NOT
        // already preloaded. We DO NOT apply these — purely informational.
        $woff2 = [];
        if (preg_match_all('#https?://[^"\'\\s)]+\.woff2#i', $html, $wm)) {
            foreach ($wm[0] as $u) {
                $u = html_entity_decode($u);
                if (!in_array($u, $woff2, true)) {
                    $woff2[] = $u;
                }
            }
        }
        $preloaded = array_map('html_entity_decode', $result['preloaded_fonts']);
        foreach ($woff2 as $u) {
            if (count($result['preload_suggestions']) >= self::PRELOAD_SUGGEST_CAP) {
                break;
            }
            if (!in_array($u, $preloaded, true)) {
                $result['preload_suggestions'][] = $u;
            }
        }

        return $result;
    }

    /**
     * @return array<int, array{code:string,severity:string,message:string,recommendation:string}>
     */
    private function evaluate_flags(array $settings, array $stats, array $rendered): array {
        $flags = [];

        if (!empty($rendered['fetched']) && !empty($rendered['external_google_fonts'])) {
            $flags[] = [
                'code'           => 'external_google_fonts_detected',
                'severity'       => 'medium',
                'message'        => sprintf(
                    'The home page still loads %d external Google Fonts resource(s) from fonts.googleapis.com / fonts.gstatic.com.',
                    (int) $rendered['external_google_count']
                ),
                'recommendation' => $settings['host_google_fonts_locally']
                    ? 'Local hosting is enabled but external Google Fonts are still being emitted (likely by the theme or a page builder before ProRank can rewrite). Review the source and consider the builder/theme font setting.'
                    : 'Enable “Host Google Fonts locally” in Asset Optimisation to remove the third-party request.',
            ];
        }

        $owner = $rendered['self_hosted_owner'] ?? 'none';
        if (
            !empty($rendered['fetched'])
            && in_array($owner, ['elementor', 'neve-theme', 'woocommerce', 'theme-or-other'], true)
            && $settings['host_google_fonts_locally']
            && empty($rendered['prorank_local_served'])
            && (int) $stats['total_fonts'] > 0
        ) {
            $flags[] = [
                'code'           => 'alternate_font_owner_detected',
                'severity'       => 'medium',
                'message'        => sprintf(
                    'Fonts on this site are self-hosted by “%s”, while ProRank has %d cached font file(s) (%s) that are not being served. Two font lanes exist.',
                    $owner,
                    (int) $stats['total_fonts'],
                    size_format((int) $stats['total_size'])
                ),
                'recommendation' => 'No action required for performance — fonts are already self-hosted. ProRank’s local-font cache is inert here; you may leave it or disable “Host Google Fonts locally” to avoid maintaining an unused cache. Do not expect ProRank to also rewrite fonts that another component already localises.',
            ];
        }

        if (!$settings['font_display_swap'] && (int) ($rendered['font_display_swap_seen'] ?? 0) === 0) {
            $flags[] = [
                'code'           => 'font_display_not_swap',
                'severity'       => 'low',
                'message'        => 'font-display:swap is not enabled and was not detected in the rendered page.',
                'recommendation' => 'Enable “Font display: swap” in Asset Optimisation so text stays visible while fonts load.',
            ];
        }

        return $flags;
    }
}
