<?php

namespace WPSN\Modules\Diagnostics\Admin;

use WPSN\Core\Branding;
use WPSN\Core\Capabilities;
use WPSN\Core\Container;
use WPSN\Core\AdminFootprintGuard;
use WPSN\Core\Http\CircuitBreaker;
use WPSN\Core\RecoveryHelper;
use WPSN\Modules\Diagnostics\DiagnosticsReportBuilder;
use WPSN\Modules\Diagnostics\SupportBundleBuilder;

defined('ABSPATH') || exit;

final class DiagnosticsAdmin
{
    private const PAGE_SLUG = 'wpsn-diagnostics';

    private Container $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    public function register(): void
    {
        add_action('admin_menu', [$this, 'addMenu']);
        add_action('admin_post_wpsn_diagnostics_export', [$this, 'handleExport']);
        add_action('admin_post_wpsn_diagnostics_update_modes', [$this, 'handleUpdateModes']);
        add_action('admin_post_wpsn_diagnostics_support_bundle', [$this, 'handleSupportBundle']);
        add_action('admin_post_wpsn_diagnostics_builders_repair', [$this, 'handleBuildersRepair']);
        add_action('admin_post_wpsn_recovery_helper_install', [$this, 'handleRecoveryHelperInstall']);
        add_action('admin_post_wpsn_recovery_helper_uninstall', [$this, 'handleRecoveryHelperUninstall']);
        add_action('admin_post_wpsn_diagnostics_clear_fatal_log', [$this, 'handleClearFatalLog']);
        add_action('admin_post_wpsn_diagnostics_clear_perf_history', [$this, 'handleClearPerfHistory']);
        add_action('admin_post_wpsn_diagnostics_clear_http_circuit', [$this, 'handleClearHttpCircuit']);
        add_action('admin_post_wpsn_diagnostics_clear_http_circuits', [$this, 'handleClearHttpCircuits']);
    }

    public function addMenu(): void
    {
        add_management_page(
            __('Compatibility & Diagnostics', 'wp-seo-next'),
            __('Compatibility', 'wp-seo-next'),
            Capabilities::CAP_TOOLS,
            self::PAGE_SLUG,
            [$this, 'render']
        );
    }

    private function pageUrl(array $args = []): string
    {
        $base = admin_url('tools.php');
        $args = array_merge(['page' => self::PAGE_SLUG], $args);
        return (string) add_query_arg($args, $base);
    }

    /**
     * @return array<string,mixed>
     */
    private function buildReport(): array
    {
        $settings = $this->container->get('settings');
        $modules = $this->container->get('modules');
        $queue = $this->container->get('queue');

        $builder = new DiagnosticsReportBuilder($settings, $modules, $queue);
        return $builder->build();
    }

    public function render(): void
    {
        if (!current_user_can(Capabilities::CAP_TOOLS)) {
            wp_die(esc_html__('You do not have permission to access this page.', 'wp-seo-next'));
        }

        $settings = $this->container->get('settings');
        $report = $this->buildReport();

        $brand = Branding::brand($settings);
        $title = __('Compatibility & Diagnostics', 'wp-seo-next');
        if ($brand !== '') {
            // translators: %s is brand name
            $title = sprintf(__('%s — Compatibility & Diagnostics', 'wp-seo-next'), $brand);
        }

        $exportUrl = wp_nonce_url(
            add_query_arg([
                'action' => 'wpsn_diagnostics_export',
            ], admin_url('admin-post.php')),
            'wpsn_diagnostics_export'
        );

        $supportUrl = wp_nonce_url(
            add_query_arg([
                'action' => 'wpsn_diagnostics_support_bundle',
            ], admin_url('admin-post.php')),
            'wpsn_diagnostics_support_bundle'
        );

        // Human-friendly summary for copy/paste.
        $mods = isset($report['wpsn']['modules_enabled']) && is_array($report['wpsn']['modules_enabled']) ? $report['wpsn']['modules_enabled'] : [];
        $modIds = [];
        foreach ($mods as $m) {
            if (!is_array($m)) {
                continue;
            }
            $id = isset($m['id']) ? (string) $m['id'] : '';
            if ($id !== '') {
                $modIds[] = $id;
            }
        }

        $ints = isset($report['integrations']) && is_array($report['integrations']) ? $report['integrations'] : [];
        $intLabels = [
            'elementor' => 'Elementor',
            'divi' => 'Divi',
            'beaver_builder' => 'Beaver Builder',
            'wpbakery' => 'WPBakery',
            'acf' => 'ACF',
            'meta_box' => 'Meta Box',
            'jetengine' => 'JetEngine',
            'woocommerce' => 'WooCommerce',
            'wpml' => 'WPML',
            'polylang' => 'Polylang',
        ];

        $detectedInts = [];
        foreach ($intLabels as $k => $label) {
            $data = isset($ints[$k]) && is_array($ints[$k]) ? $ints[$k] : [];
            if (!empty($data['detected'])) {
                $detectedInts[] = $label;
            }
        }

        $counts = isset($report['queue']['counts']) && is_array($report['queue']['counts']) ? $report['queue']['counts'] : [];
        $summaryLines = [];
        $summaryLines[] = 'WP SEO Next — Diagnostics summary';
        $summaryLines[] = 'Generated (UTC): ' . gmdate('Y-m-d H:i:s');
        $summaryLines[] = 'Home URL: ' . (string) ($report['site']['home_url'] ?? '');
        $summaryLines[] = 'Site URL: ' . (string) ($report['site']['site_url'] ?? '');
        $summaryLines[] = 'SSL: ' . (!empty($report['site']['is_ssl']) ? 'yes' : 'no') . ' · Locale: ' . (string) ($report['site']['locale'] ?? '') . ' · Multisite: ' . (!empty($report['site']['multisite']) ? 'yes' : 'no');
        $summaryLines[] = 'WP: ' . (string) ($report['wp']['version'] ?? '') . ' · PHP: ' . (string) ($report['php']['version'] ?? '') . ' · Env: ' . (string) ($report['wp']['environment_type'] ?? '');
        $summaryLines[] = 'WPSN: ' . (string) ($report['wpsn']['version'] ?? '') . ' · Local-only: ' . (!empty($report['wpsn']['privacy_local_only']) ? 'enabled' : 'disabled');
        $summaryLines[] = 'OpenAI configured: ' . (!empty($report['features']['openai_configured']) ? 'yes' : 'no') . ' · GSC configured: ' . (!empty($report['features']['gsc_configured']) ? 'yes' : 'no') . ' · IndexNow key: ' . (!empty($report['features']['indexnow_configured']) ? 'yes' : 'no');
        $summaryLines[] = 'Queue: mode=' . (string) ($report['queue']['mode'] ?? '') . ' · interval=' . (string) ($report['queue']['interval_seconds'] ?? '') . 's · max_jobs=' . (string) ($report['queue']['max_jobs_per_run'] ?? '');
        $summaryLines[] = 'Jobs: pending=' . (string) ((int) ($counts['pending'] ?? 0)) . ' · running=' . (string) ((int) ($counts['running'] ?? 0)) . ' · done=' . (string) ((int) ($counts['done'] ?? 0)) . ' · failed=' . (string) ((int) ($counts['failed'] ?? 0));

        $db = isset($report['db']) && is_array($report['db']) ? $report['db'] : [];
        $totalBytes = (int) ($db['total_bytes'] ?? 0);
        $largest = isset($db['largest_table']) && is_array($db['largest_table']) ? $db['largest_table'] : [];
        $largestName = isset($largest['name']) ? (string) $largest['name'] : '';
        $largestBytes = (int) ($largest['bytes'] ?? 0);
        $summaryLines[] = 'DB tables: total=' . (string) round($totalBytes / 1024 / 1024, 2) . 'MB · largest=' . ($largestName !== '' ? $largestName : '—') . ' (' . (string) round($largestBytes / 1024 / 1024, 2) . 'MB)';

        $cron = isset($report['cron']) && is_array($report['cron']) ? $report['cron'] : [];
        $events = isset($cron['wpsn_events']) && is_array($cron['wpsn_events']) ? $cron['wpsn_events'] : [];
        $summaryLines[] = 'Cron events (wpsn_*): ' . (string) count($events);
        $summaryLines[] = 'Enabled modules (' . count($modIds) . '): ' . (empty($modIds) ? '—' : implode(', ', $modIds));
        $summaryLines[] = 'Detected integrations: ' . (empty($detectedInts) ? '—' : implode(', ', $detectedInts));

        $summary = implode("\n", $summaryLines);

        echo '<div class="wrap">';
        echo '<h1>' . esc_html($title) . '</h1>';
        echo '<p class="description">' . esc_html__('Use this page to verify environment, module status and integration detection. Export the report when sharing with support or your team.', 'wp-seo-next') . '</p>';

        if (!empty($_GET['wpsn_diag_notice'])) {
            $n = sanitize_key((string) wp_unslash($_GET['wpsn_diag_notice']));
            if ($n === 'modes_saved') {
                echo '<div class="notice notice-success"><p>' . esc_html__('Settings updated.', 'wp-seo-next') . '</p></div>';
            }
            if ($n === 'permission') {
                echo '<div class="notice notice-error"><p>' . esc_html__('You do not have permission to do this action.', 'wp-seo-next') . '</p></div>';
            }
            if ($n === 'fatal_cleared') {
                echo '<div class="notice notice-success"><p>' . esc_html__('Fatal error log cleared.', 'wp-seo-next') . '</p></div>';
            }
            if ($n === 'perf_cleared') {
                echo '<div class="notice notice-success"><p>' . esc_html__('Performance history cleared.', 'wp-seo-next') . '</p></div>';
            }
            if ($n === 'http_circuit_cleared') {
                echo '<div class="notice notice-success"><p>' . esc_html__('HTTP circuit breaker cleared.', 'wp-seo-next') . '</p></div>';
            }
            if ($n === 'http_circuits_cleared') {
                echo '<div class="notice notice-success"><p>' . esc_html__('All HTTP circuit breakers cleared.', 'wp-seo-next') . '</p></div>';
            }
            if ($n === 'builders_repaired') {
                echo '<div class="notice notice-success"><p>' . esc_html__('Builder integrations repaired (settings updated).', 'wp-seo-next') . '</p></div>';
            }
        

if ($n === 'recovery_installed' || $n === 'recovery_removed' || $n === 'recovery_failed') {
    $msg = isset($_GET['wpsn_diag_msg']) ? rawurldecode((string) wp_unslash($_GET['wpsn_diag_msg'])) : '';
    if ($msg === '') {
        $msg = $n === 'recovery_installed' ? __('Recovery helper installed.', 'wp-seo-next') : ($n === 'recovery_removed' ? __('Recovery helper removed.', 'wp-seo-next') : __('Recovery helper action failed.', 'wp-seo-next'));
    }
    $cls = $n === 'recovery_failed' ? 'notice notice-error' : 'notice notice-success';
    echo '<div class="' . esc_attr($cls) . '"><p>' . esc_html($msg) . '</p></div>';
}
        }


        echo '<p>';
        echo '<a class="button button-primary" href="' . esc_url($supportUrl) . '">' . esc_html__('Download support bundle', 'wp-seo-next') . '</a> ';
        echo '<a class="button" href="' . esc_url($exportUrl) . '" style="margin-left:6px;">' . esc_html__('Download diagnostics report (JSON)', 'wp-seo-next') . '</a> ';
        echo '<a class="button" href="' . esc_url(admin_url('tools.php?page=wpsn-platform-ops')) . '" style="margin-left:6px;">' . esc_html__('Platform Ops', 'wp-seo-next') . '</a> ';
        echo '<button type="button" class="button" id="wpsn-diag-copy-summary">' . esc_html__('Copy diagnostics summary', 'wp-seo-next') . '</button>';
        echo ' <span id="wpsn-diag-copied" style="display:none; margin-left:8px; color:#0a7; font-weight:600;">' . esc_html__('Copied!', 'wp-seo-next') . '</span>';
        echo '</p>';

        echo '<textarea id="wpsn-diag-summary" readonly style="position:absolute;left:-9999px;top:-9999px;">' . esc_textarea((string) $summary) . '</textarea>';
        echo '<script>(function(){
            var btn = document.getElementById("wpsn-diag-copy-summary");
            var el = document.getElementById("wpsn-diag-summary");
            var ok = document.getElementById("wpsn-diag-copied");
            if(!btn || !el){return;}
            function showOk(){ if(!ok){return;} ok.style.display = "inline"; setTimeout(function(){ ok.style.display = "none"; }, 2500); }
            btn.addEventListener("click", function(){
                var text = el.value || "";
                if(text === ""){ return; }
                if(navigator.clipboard && navigator.clipboard.writeText){
                    navigator.clipboard.writeText(text).then(showOk).catch(function(){
                        el.focus(); el.select();
                        try{ document.execCommand("copy"); showOk(); }catch(e){}
                    });
                    return;
                }
                el.focus(); el.select();
                try{ document.execCommand("copy"); showOk(); }catch(e){}
            });
        })();</script>';


        // Compatibility & Recovery (Safe mode, compatibility mode, perf budget).
        $compat = isset($report['compatibility']) && is_array($report['compatibility']) ? $report['compatibility'] : [];
        $seoPlugins = isset($compat['other_seo_plugins']) && is_array($compat['other_seo_plugins']) ? $compat['other_seo_plugins'] : [];

        $safeModeConst = defined('WPSN_SAFE_MODE') && (bool) WPSN_SAFE_MODE;
        $safeMode = !empty($compat['safe_mode']);
        $disableOutput = !empty($compat['disable_output']);
        $disableOutputConst = !empty($compat['disable_output_forced_by_constant']);
        $disableOutputForcedByConflict = !empty($compat['disable_output_forced_by_conflict']);
        $autoDisableOnConflict = !empty($compat['auto_disable_output_on_conflict']);

        $perfProbe = isset($report['performance_probe']) && is_array($report['performance_probe']) ? $report['performance_probe'] : [];
        $perfEnabled = !empty($perfProbe['enabled']);

        $minFootprint = (bool) $settings->get('performance.admin.minimize_admin_footprint', false);
        $ajaxEnabled = (bool) $settings->get('performance.admin.ajax_enabled', false);
        $ajaxLiteBoot = (bool) $settings->get('performance.admin.ajax_lite_boot', true);
        $collectMetrics = (bool) $settings->get('performance.admin.collect_metrics', false);
        $recordHistory = (bool) $settings->get('performance.admin.record_history', false);

        $hasSeoConflict = false;
        foreach ($seoPlugins as $row) {
            if (is_array($row) && !empty($row['detected'])) {
                $hasSeoConflict = true;
                break;
            }
        }

        echo '<h2>' . esc_html__('Compatibility & Recovery', 'wp-seo-next') . '</h2>';
        echo '<p class="description">' . esc_html__('Use these controls when another SEO plugin is active, or when you need to reduce wp-admin overhead. These are reversible and do not delete data.', 'wp-seo-next') . '</p>';

        if ($safeModeConst) {
            echo '<div class="notice notice-warning"><p><strong>' . esc_html__('Safe mode is forced by wp-config.', 'wp-seo-next') . '</strong> ' . esc_html__('Remove WPSN_SAFE_MODE to restore normal behavior.', 'wp-seo-next') . '</p></div>';
        }

        if ($disableOutputConst) {
            echo '<div class="notice notice-warning"><p><strong>' . esc_html__('Frontend output is forced disabled by wp-config.', 'wp-seo-next') . '</strong> ' . esc_html__('Remove WPSN_DISABLE_OUTPUT to restore normal behavior.', 'wp-seo-next') . '</p></div>';
        }

        if ($disableOutputForcedByConflict) {
            echo '<div class="notice notice-info"><p><strong>' . esc_html__('Auto compatibility safeguard is active.', 'wp-seo-next') . '</strong> ' . esc_html__('Another SEO plugin was detected, so WP SEO Next disabled its frontend output modules to prevent duplicate tags.', 'wp-seo-next') . '</p></div>';
        }

        // Detected SEO plugins (potential conflicts).
        echo '<h3>' . esc_html__('Detected SEO plugins', 'wp-seo-next') . '</h3>';
        if (!$hasSeoConflict) {
            echo '<p>' . esc_html__('No known SEO plugins were detected.', 'wp-seo-next') . '</p>';
        } else {
            echo '<p class="description">' . esc_html__('If another SEO plugin outputs title/meta/schema, consider enabling Compatibility mode to avoid duplicate tags.', 'wp-seo-next') . '</p>';
            echo '<ul style="list-style: disc; padding-left: 18px;">';
            foreach ($seoPlugins as $id => $row) {
                if (!is_array($row) || empty($row['detected'])) {
                    continue;
                }
                $name = isset($row['name']) ? (string) $row['name'] : (string) $id;
                $signal = isset($row['signal']) ? (string) $row['signal'] : '';
                echo '<li><strong>' . esc_html($name) . '</strong>' . ($signal !== '' ? ' <code>' . esc_html($signal) . '</code>' : '') . '</li>';
            }
            echo '</ul>';

            if (!$disableOutput) {
                echo '<div class="notice notice-warning"><p>' . esc_html__('Potential conflict detected. WP SEO Next output modules are currently enabled.', 'wp-seo-next') . '</p></div>';
            }
        }

        // Modes form.
        echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
        echo '<input type="hidden" name="action" value="wpsn_diagnostics_update_modes" />';
        wp_nonce_field('wpsn_diagnostics_update_modes', 'wpsn_nonce');

        echo '<table class="widefat striped" style="max-width: 900px;">';
        echo '<tbody>';

        echo '<tr><th style="width:280px;">' . esc_html__('Safe mode (disable editor integrations)', 'wp-seo-next') . '</th><td>';
        echo '<label><input type="checkbox" name="compatibility_safe_mode" value="1" ' . checked($safeMode, true, false) . ' /> ' . esc_html__('Disable block editor + page builder integrations (recommended for recovery).', 'wp-seo-next') . '</label>';
        echo '<p class="description">' . esc_html__('This does not change frontend output. For emergency recovery you can also set WPSN_SAFE_MODE in wp-config.php.', 'wp-seo-next') . '</p>';
        echo '</td></tr>';

        echo '<tr><th>' . esc_html__('Compatibility mode (disable frontend output)', 'wp-seo-next') . '</th><td>';
        echo '<label><input type="checkbox" name="compatibility_disable_output" value="1" ' . checked($disableOutput, true, false) . ' /> ' . esc_html__('Disable Meta Tags, Social, Schema, Sitemap, Robots and Breadcrumbs modules.', 'wp-seo-next') . '</label>';
        echo '<p class="description">' . esc_html__('Use this when another SEO plugin owns the frontend output, but you still want WP SEO Next tools (redirects, audits, bulk, etc.).', 'wp-seo-next') . '</p>';
        echo '<p class="description">' . esc_html__('Tip: you can enable “Auto-disable output on conflict” below to prevent duplicates during migrations.', 'wp-seo-next') . '</p>';
        echo '</td></tr>';

        echo '<tr><th>' . esc_html__('Auto-disable output on SEO conflict', 'wp-seo-next') . '</th><td>';
        echo '<label><input type="checkbox" name="compatibility_auto_disable_output_on_conflict" value="1" ' . checked($autoDisableOnConflict, true, false) . ' /> ' . esc_html__('If another SEO plugin is detected, disable WP SEO Next output modules automatically (runtime safeguard).', 'wp-seo-next') . '</label>';
        echo '<p class="description">' . esc_html__('This does not change stored module settings. When the conflict disappears, WP SEO Next output returns (unless you enabled Compatibility mode above).', 'wp-seo-next') . '</p>';
        echo '</td></tr>';

        echo '<tr><th>' . esc_html__('Minimize admin footprint', 'wp-seo-next') . '</th><td>';
        echo '<label><input type="checkbox" name="performance_minimize_admin_footprint" value="1" ' . checked($minFootprint, true, false) . ' /> ' . esc_html__('Turn off editor integrations automatically to keep wp-admin fast.', 'wp-seo-next') . '</label>';
        echo '</td></tr>';

        echo '<tr><th>' . esc_html__('AJAX live mode (admin-ajax.php)', 'wp-seo-next') . '</th><td>';
        echo '<label><input type="checkbox" name="performance_admin_ajax_enabled" value="1" ' . checked($ajaxEnabled, true, false) . ' /> ' . esc_html__('Enable optional live mode on WP SEO Next tools (uses admin-ajax.php).', 'wp-seo-next') . '</label>';
        echo '<p class="description">' . esc_html__('Disabled by default for stability on shared hosting. When off, WP SEO Next will avoid loading AJAX-heavy admin scripts and will reject wpsn_* admin-ajax requests.', 'wp-seo-next') . '</p>';
        echo '<p class="description">' . esc_html__('Tip: you can also hard-disable with define("WPSN_DISABLE_AJAX", true) in wp-config.php.', 'wp-seo-next') . '</p>';
        echo '</td></tr>';

        echo '<tr><th>' . esc_html__('AJAX lite boot (recommended)', 'wp-seo-next') . '</th><td>';
        echo '<label><input type="checkbox" name="performance_admin_ajax_lite_boot" value="1" ' . checked($ajaxLiteBoot, true, false) . ' /> ' . esc_html__('Do not fully boot WP SEO Next on unrelated admin-ajax.php requests (reduces 503 errors).', 'wp-seo-next') . '</label>';
        echo '<p class="description">' . esc_html__('Keeps admin-ajax lightweight on shared hosting. WP SEO Next AJAX actions still work when AJAX live mode is enabled.', 'wp-seo-next') . '</p>';
        echo '<p class="description">' . esc_html__('Tip: you can force-disable with define("WPSN_DISABLE_AJAX_LITE_BOOT", true) in wp-config.php.', 'wp-seo-next') . '</p>';
        echo '</td></tr>';

        echo '<tr><th>' . esc_html__('Collect performance metrics', 'wp-seo-next') . '</th><td>';
        echo '<label><input type="checkbox" name="performance_collect_metrics" value="1" ' . checked($collectMetrics, true, false) . ' /> ' . esc_html__('Enable lightweight request metrics (shown below).', 'wp-seo-next') . '</label>';
        echo '</td></tr>';

        echo '<tr><th>' . esc_html__('Record performance history', 'wp-seo-next') . '</th><td>';
        echo '<label><input type="checkbox" name="performance_record_history" value="1" ' . checked($recordHistory, true, false) . ' /> ' . esc_html__('Store last 50 performance snapshots (WP SEO Next pages only).', 'wp-seo-next') . '</label>';
        echo '<p class="description">' . esc_html__('Useful to compare regressions after updates. Disabled by default and has near-zero overhead when off.', 'wp-seo-next') . '</p>';
        echo '</td></tr>';

        echo '<tr><th>' . esc_html__('Frontend performance contract', 'wp-seo-next') . '</th><td>';
        $frontendContract = (bool) $settings->get('performance.frontend.contract_enabled', true);
        echo '<label><input type="checkbox" name="performance_frontend_contract" value="1" ' . checked($frontendContract, true, false) . ' /> ' . esc_html__('Prevent WP SEO Next from enqueueing frontend JS/CSS except explicit editor contexts.', 'wp-seo-next') . '</label>';
        echo '<p class="description">' . esc_html__('Recommended on production sites (keeps public pages clean and reduces caching risks).', 'wp-seo-next') . '</p>';
        echo '</td></tr>';

        echo '<tr><th>' . esc_html__('Frontend Inspector on-demand', 'wp-seo-next') . '</th><td>';
        $inspectorOnDemand = (bool) $settings->get('performance.frontend.inspector_on_demand', true);
        echo '<label><input type="checkbox" name="performance_frontend_inspector_on_demand" value="1" ' . checked($inspectorOnDemand, true, false) . ' /> ' . esc_html__('Load the Frontend Inspector only when requested (admin bar shortcut adds ?wpsn_inspector=1).', 'wp-seo-next') . '</label>';
        echo '<p class="description">' . esc_html__('This prevents page caches from accidentally serving the inspector UI to visitors.', 'wp-seo-next') . '</p>';
        echo '</td></tr>';

        echo '</tbody></table>';

        echo '<p><button type="submit" class="button button-primary">' . esc_html__('Save modes', 'wp-seo-next') . '</button></p>';
        echo '</form>';

// Emergency Recovery Helper (MU-plugin).
echo '<h3>' . esc_html__('Emergency Recovery Helper (MU-plugin)', 'wp-seo-next') . '</h3>';
echo '<p class="description">' . esc_html__('Installs a must-use helper that adds recovery buttons on WordPress fatal error pages when the fatal originated from WP SEO Next (disable plugin / restore last config snapshot).', 'wp-seo-next') . '</p>';

$recoveryInstalled = RecoveryHelper::isInstalled();
$muFile = RecoveryHelper::muPluginFile();

if ($recoveryInstalled) {
    echo '<div class="notice notice-success inline"><p>' . esc_html__('Recovery helper is installed.', 'wp-seo-next') . ' <code>' . esc_html($muFile) . '</code></p></div>';
} else {
    echo '<div class="notice notice-warning inline"><p>' . esc_html__('Recovery helper is not installed.', 'wp-seo-next') . ' <code>' . esc_html($muFile) . '</code></p></div>';
}

echo '<div style="margin:10px 0;">';
if (!$recoveryInstalled) {
    echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="display:inline-block; margin-right:8px;">';
    echo '<input type="hidden" name="action" value="wpsn_recovery_helper_install" />';
    wp_nonce_field('wpsn_recovery_helper_install', 'wpsn_nonce');
    echo '<button type="submit" class="button button-secondary">' . esc_html__('Install Recovery Helper', 'wp-seo-next') . '</button>';
    echo '</form>';
} else {
    echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="display:inline-block; margin-right:8px;">';
    echo '<input type="hidden" name="action" value="wpsn_recovery_helper_uninstall" />';
    wp_nonce_field('wpsn_recovery_helper_uninstall', 'wpsn_nonce');
    echo '<button type="submit" class="button button-secondary" onclick="return confirm(\'' . esc_js(__('Remove recovery helper MU-plugin?', 'wp-seo-next')) . '\');">' . esc_html__('Remove Recovery Helper', 'wp-seo-next') . '</button>';
    echo '</form>';
}


$disableUrlAdmin = RecoveryHelper::recoveryUrlAdminOnly('disable');
$safeUrlAdmin = RecoveryHelper::recoveryUrlAdminOnly('safe_mode');
$outUrlAdmin = RecoveryHelper::recoveryUrlAdminOnly('disable_output');
$restoreUrlAdmin = RecoveryHelper::recoveryUrlAdminOnly('restore_config');
$disableUrlSigned = RecoveryHelper::recoveryUrl('disable');
$safeUrlSigned = RecoveryHelper::recoveryUrl('safe_mode');
$outUrlSigned = RecoveryHelper::recoveryUrl('disable_output');
$restoreUrlSigned = RecoveryHelper::recoveryUrl('restore_config');

echo '<details style="display:inline-block; vertical-align:top; max-width: 900px;">';
echo '<summary>' . esc_html__('Recovery URLs', 'wp-seo-next') . '</summary>';
echo '<div style="margin-top:8px;">';

echo '<p style="margin:6px 0;"><strong>' . esc_html__('Admin-only (requires you are logged in):', 'wp-seo-next') . '</strong></p>';
echo '<p style="margin:6px 0;"><strong>' . esc_html__('Disable WP SEO Next:', 'wp-seo-next') . '</strong><br/><code style="word-break:break-all;">' . esc_html($disableUrlAdmin) . '</code></p>';
echo '<p style="margin:6px 0;"><strong>' . esc_html__('Enable Safe Mode:', 'wp-seo-next') . '</strong><br/><code style="word-break:break-all;">' . esc_html($safeUrlAdmin) . '</code></p>';
echo '<p style="margin:6px 0;"><strong>' . esc_html__('Disable frontend output:', 'wp-seo-next') . '</strong><br/><code style="word-break:break-all;">' . esc_html($outUrlAdmin) . '</code></p>';
echo '<p style="margin:6px 0;"><strong>' . esc_html__('Restore last config snapshot:', 'wp-seo-next') . '</strong><br/><code style="word-break:break-all;">' . esc_html($restoreUrlAdmin) . '</code></p>';

echo '<hr style="margin:12px 0;" />';

echo '<p style="margin:6px 0;"><strong>' . esc_html__('Signed (works without login — keep private):', 'wp-seo-next') . '</strong></p>';
echo '<p style="margin:6px 0;"><strong>' . esc_html__('Disable WP SEO Next:', 'wp-seo-next') . '</strong><br/><code style="word-break:break-all;">' . esc_html($disableUrlSigned) . '</code></p>';
echo '<p style="margin:6px 0;"><strong>' . esc_html__('Enable Safe Mode:', 'wp-seo-next') . '</strong><br/><code style="word-break:break-all;">' . esc_html($safeUrlSigned) . '</code></p>';
echo '<p style="margin:6px 0;"><strong>' . esc_html__('Disable frontend output:', 'wp-seo-next') . '</strong><br/><code style="word-break:break-all;">' . esc_html($outUrlSigned) . '</code></p>';
echo '<p style="margin:6px 0;"><strong>' . esc_html__('Restore last config snapshot:', 'wp-seo-next') . '</strong><br/><code style="word-break:break-all;">' . esc_html($restoreUrlSigned) . '</code></p>';

echo '<p class="description" style="margin:10px 0 0;">' . esc_html__('If the site shows “There has been a critical error” and the MU-helper is installed: open that fatal page while logged in as admin — you will see buttons to disable WP SEO Next / restore snapshot.', 'wp-seo-next') . '</p>';
echo '</div>';
echo '</details>';

echo '</div>';

        // Fatal errors tracker (plugin-scoped).
        echo '<h3 id="wpsn-fatal-log">' . esc_html__('Recent fatal errors (WP SEO Next)', 'wp-seo-next') . '</h3>';
        echo '<p class="description">' . esc_html__('Captured via a best-effort shutdown handler when a fatal error originates from this plugin. Helps debugging when WP recovery emails are missed.', 'wp-seo-next') . '</p>';

        $fatalLog = function_exists('get_option') ? get_option('wpsn_fatal_log', []) : [];
        if (!is_array($fatalLog)) {
            $fatalLog = [];
        }

        echo '<div style="max-width: 900px;">';

        if (empty($fatalLog)) {
            echo '<p>' . esc_html__('No plugin fatal errors recorded.', 'wp-seo-next') . '</p>';
        } else {
            echo '<p style="margin:6px 0 12px;"><strong>' . esc_html(sprintf(__('Items: %d (newest first)', 'wp-seo-next'), count($fatalLog))) . '</strong></p>';

            echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="margin:0 0 10px;">';
            echo '<input type="hidden" name="action" value="wpsn_diagnostics_clear_fatal_log" />';
            wp_nonce_field('wpsn_diagnostics_clear_fatal_log', 'wpsn_nonce');
            echo '<button type="submit" class="button button-secondary" onclick="return confirm(\'' . esc_js(__('Clear the stored fatal error log?', 'wp-seo-next')) . '\');">' . esc_html__('Clear fatal log', 'wp-seo-next') . '</button>';
            echo '</form>';

            echo '<table class="widefat striped"><thead><tr>';
            echo '<th style="width:160px;">' . esc_html__('Time (UTC)', 'wp-seo-next') . '</th>';
            echo '<th>' . esc_html__('Message', 'wp-seo-next') . '</th>';
            echo '<th style="width:220px;">' . esc_html__('File', 'wp-seo-next') . '</th>';
            echo '<th style="width:70px;">' . esc_html__('Line', 'wp-seo-next') . '</th>';
            echo '</tr></thead><tbody>';

            $shown = 0;
            foreach ($fatalLog as $row) {
                if (!is_array($row)) {
                    continue;
                }
                $at = isset($row['at_utc']) ? sanitize_text_field((string) $row['at_utc']) : '';
                $msg = isset($row['message']) ? sanitize_text_field((string) $row['message']) : '';
                $file = isset($row['file']) ? sanitize_text_field((string) $row['file']) : '';
                $line = isset($row['line']) ? (int) $row['line'] : 0;
                if (strlen($msg) > 260) {
                    $msg = substr($msg, 0, 260) . '…';
                }
                if (strlen($file) > 80) {
                    $file = '…' . substr($file, -80);
                }

                echo '<tr>';
                echo '<td><code>' . esc_html($at) . '</code></td>';
                echo '<td>' . esc_html($msg) . '</td>';
                echo '<td><code>' . esc_html($file) . '</code></td>';
                echo '<td><code>' . esc_html((string) $line) . '</code></td>';
                echo '</tr>';

                $shown++;
                if ($shown >= 10) {
                    break;
                }
            }

            echo '</tbody></table>';

            if (count($fatalLog) > 10) {
                echo '<p class="description" style="margin-top:8px;">' . esc_html__('Showing latest 10 items. Full list is included in the Support Bundle JSON.', 'wp-seo-next') . '</p>';
            }
        }

        echo '</div>';

        // Performance probe section.
        echo '<h3>' . esc_html__('Performance snapshot (this request)', 'wp-seo-next') . '</h3>';

        if (!$perfEnabled) {
            echo '<p class="description">' . esc_html__('Performance probe is disabled. Enable “Collect performance metrics” above to see timings.', 'wp-seo-next') . '</p>';
        } else {
            $totalMs = isset($perfProbe['total_ms']) ? (int) $perfProbe['total_ms'] : 0;
            $queries = isset($perfProbe['queries']) ? (int) $perfProbe['queries'] : 0;
            $memBytes = isset($perfProbe['memory_peak_bytes']) ? (int) $perfProbe['memory_peak_bytes'] : 0;

            $fmtMb = static function (int $bytes): string {
                if ($bytes <= 0) {
                    return '0 MB';
                }
                return round($bytes / 1024 / 1024, 2) . ' MB';
            };

            echo '<table class="widefat striped" style="max-width: 900px;"><tbody>';
            $this->row(__('Total request (ms)', 'wp-seo-next'), (string) $totalMs);
            $this->row(__('DB queries (delta)', 'wp-seo-next'), (string) $queries);
            $this->row(__('Peak memory', 'wp-seo-next'), $fmtMb($memBytes));

            $assetSnap = AdminFootprintGuard::snapshot();
            $scripts = isset($assetSnap['scripts_enqueued']) && is_array($assetSnap['scripts_enqueued']) ? $assetSnap['scripts_enqueued'] : [];
            $styles  = isset($assetSnap['styles_enqueued']) && is_array($assetSnap['styles_enqueued']) ? $assetSnap['styles_enqueued'] : [];
            $removedScripts = isset($assetSnap['removed_scripts']) && is_array($assetSnap['removed_scripts']) ? $assetSnap['removed_scripts'] : [];
            $removedStyles  = isset($assetSnap['removed_styles']) && is_array($assetSnap['removed_styles']) ? $assetSnap['removed_styles'] : [];

            $this->row(__('WPSN scripts enqueued', 'wp-seo-next'), (string) count($scripts));
            $this->row(__('WPSN styles enqueued', 'wp-seo-next'), (string) count($styles));
            $this->row(__('Asset guard removed', 'wp-seo-next'), (string) (count($removedScripts) + count($removedStyles)));

            $metrics = isset($perfProbe['metrics_ms']) && is_array($perfProbe['metrics_ms']) ? $perfProbe['metrics_ms'] : [];
            foreach ($metrics as $k => $ms) {
                $k = (string) $k;
                if ($k === '') {
                    continue;
                }
                $this->row(sprintf(__('Metric: %s (ms)', 'wp-seo-next'), $k), (string) ((int) round((float) $ms)));
            }

            echo '</tbody></table>';

            // Optional details for troubleshooting footprint regressions.
            echo '<details style="margin-top:10px; max-width:900px;">';
            echo '<summary>' . esc_html__('Admin assets details', 'wp-seo-next') . '</summary>';
            echo '<div style="margin-top:8px;">';
            echo '<p style="margin:6px 0;"><strong>' . esc_html__('Last hook:', 'wp-seo-next') . '</strong> <code>' . esc_html((string) ($assetSnap['last_hook'] ?? '')) . '</code></p>';
            echo '<p style="margin:6px 0;"><strong>' . esc_html__('Screen base:', 'wp-seo-next') . '</strong> <code>' . esc_html((string) ($assetSnap['last_screen_base'] ?? '')) . '</code></p>';
            echo '<p style="margin:10px 0 4px;"><strong>' . esc_html__('Scripts enqueued:', 'wp-seo-next') . '</strong></p>';
            echo '<pre style="background:#0b1220; color:#e9eef7; padding:10px 12px; border-radius:10px; border:1px solid rgba(0,0,0,.15); overflow:auto; max-height:220px;">' . esc_html(wp_json_encode($scripts, JSON_PRETTY_PRINT)) . '</pre>';
            echo '<p style="margin:10px 0 4px;"><strong>' . esc_html__('Styles enqueued:', 'wp-seo-next') . '</strong></p>';
            echo '<pre style="background:#0b1220; color:#e9eef7; padding:10px 12px; border-radius:10px; border:1px solid rgba(0,0,0,.15); overflow:auto; max-height:220px;">' . esc_html(wp_json_encode($styles, JSON_PRETTY_PRINT)) . '</pre>';
            if (!empty($removedScripts) || !empty($removedStyles)) {
                echo '<p style="margin:10px 0 4px;"><strong>' . esc_html__('Removed by guard:', 'wp-seo-next') . '</strong></p>';
                echo '<pre style="background:#0b1220; color:#e9eef7; padding:10px 12px; border-radius:10px; border:1px solid rgba(0,0,0,.15); overflow:auto; max-height:220px;">' . esc_html(wp_json_encode([
                    'scripts' => $removedScripts,
                    'styles' => $removedStyles,
                ], JSON_PRETTY_PRINT)) . '</pre>';
            }
            echo '</div></details>';
        }

        // Performance history (opt-in).
        echo '<h3 style="margin-top:18px;">' . esc_html__('Performance history (last 50)', 'wp-seo-next') . '</h3>';
        if (!$collectMetrics) {
            echo '<p class="description">' . esc_html__('Enable “Collect performance metrics” above to record history.', 'wp-seo-next') . '</p>';
        } elseif (!$recordHistory) {
            echo '<p class="description">' . esc_html__('History recording is disabled. Turn it on above to store a small ring buffer for regression debugging.', 'wp-seo-next') . '</p>';
        } else {
            $items = \WPSN\Core\PerfHistory::all();
            if (empty($items)) {
                echo '<p>' . esc_html__('No history captured yet. Visit a couple of WP SEO Next pages and refresh this screen.', 'wp-seo-next') . '</p>';
            } else {
                echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="margin:8px 0 10px;">';
                echo '<input type="hidden" name="action" value="wpsn_diagnostics_clear_perf_history" />';
                wp_nonce_field('wpsn_diagnostics_clear_perf_history', 'wpsn_nonce');
                echo '<button type="submit" class="button button-secondary" onclick="return confirm(\'' . esc_js(__('Clear stored performance history?', 'wp-seo-next')) . '\');">' . esc_html__('Clear history', 'wp-seo-next') . '</button>';
                echo '</form>';

                echo '<div style="max-width: 900px;">';
                echo '<table class="widefat striped"><thead><tr>';
                echo '<th style="width:170px;">' . esc_html__('Time (UTC)', 'wp-seo-next') . '</th>';
                echo '<th>' . esc_html__('Page', 'wp-seo-next') . '</th>';
                echo '<th style="width:90px;">' . esc_html__('Total ms', 'wp-seo-next') . '</th>';
                echo '<th style="width:90px;">' . esc_html__('DB q', 'wp-seo-next') . '</th>';
                echo '<th style="width:110px;">' . esc_html__('Peak mem', 'wp-seo-next') . '</th>';
                echo '<th>' . esc_html__('Top metric', 'wp-seo-next') . '</th>';
                echo '</tr></thead><tbody>';

                $shown = 0;
                foreach ($items as $row) {
                    if (!is_array($row)) {
                        continue;
                    }

                    $at = isset($row['at_utc']) ? sanitize_text_field((string) $row['at_utc']) : '';
                    $page = isset($row['page']) ? sanitize_key((string) $row['page']) : '';
                    $screen = isset($row['screen_base']) ? sanitize_key((string) $row['screen_base']) : '';
                    $uri = isset($row['request_uri']) ? sanitize_text_field((string) $row['request_uri']) : '';

                    $totalMs = isset($row['total_ms']) ? (int) $row['total_ms'] : 0;
                    $q = isset($row['queries']) ? (int) $row['queries'] : 0;
                    $memBytes = isset($row['memory_peak_bytes']) ? (int) $row['memory_peak_bytes'] : 0;
                    $memMb = $memBytes > 0 ? round($memBytes / 1024 / 1024, 2) . ' MB' : '0 MB';

                    $metrics = isset($row['metrics_ms']) && is_array($row['metrics_ms']) ? $row['metrics_ms'] : [];
                    $topMetric = '';
                    if (!empty($metrics)) {
                        arsort($metrics);
                        $k = (string) array_key_first($metrics);
                        $v = (float) ($metrics[$k] ?? 0);
                        $topMetric = $k !== '' ? ($k . ': ' . (string) ((int) round($v)) . 'ms') : '';
                    }

                    $pageLabel = $page !== '' ? $page : ($screen !== '' ? $screen : '—');
                    if ($uri !== '' && strlen($uri) > 90) {
                        $uri = '…' . substr($uri, -90);
                    }

                    echo '<tr>';
                    echo '<td><code>' . esc_html($at) . '</code></td>';
                    echo '<td><code>' . esc_html($pageLabel) . '</code><div class="description" style="margin-top:2px;">' . esc_html($uri) . '</div></td>';
                    echo '<td><code>' . esc_html((string) $totalMs) . '</code></td>';
                    echo '<td><code>' . esc_html((string) $q) . '</code></td>';
                    echo '<td><code>' . esc_html($memMb) . '</code></td>';
                    echo '<td><code>' . esc_html($topMetric !== '' ? $topMetric : '—') . '</code></td>';
                    echo '</tr>';

                    $shown++;
                    if ($shown >= 20) {
                        break;
                    }
                }

                echo '</tbody></table>';
                if (count($items) > 20) {
                    echo '<p class="description" style="margin-top:8px;">' . esc_html__('Showing latest 20 items.', 'wp-seo-next') . '</p>';
                }
                echo '</div>';
            }
        }


        // Environment summary.
        echo '<h2>' . esc_html__('Environment', 'wp-seo-next') . '</h2>';
        echo '<table class="widefat striped">';
        echo '<tbody>';
        $this->row(__('Home URL', 'wp-seo-next'), (string) ($report['site']['home_url'] ?? ''));
        $this->row(__('Site URL', 'wp-seo-next'), (string) ($report['site']['site_url'] ?? ''));
        $this->row(__('SSL', 'wp-seo-next'), !empty($report['site']['is_ssl']) ? __('Yes', 'wp-seo-next') : __('No', 'wp-seo-next'));
        $this->row(__('Locale', 'wp-seo-next'), (string) ($report['site']['locale'] ?? ''));
        $this->row(__('Multisite', 'wp-seo-next'), !empty($report['site']['multisite']) ? __('Yes', 'wp-seo-next') : __('No', 'wp-seo-next'));
        $this->row(__('WordPress', 'wp-seo-next'), (string) ($report['wp']['version'] ?? ''));
        $this->row(__('Environment type', 'wp-seo-next'), (string) ($report['wp']['environment_type'] ?? ''));
        $this->row(__('External object cache', 'wp-seo-next'), !empty($report['wp']['object_cache']) ? __('Yes', 'wp-seo-next') : __('No', 'wp-seo-next'));
        $this->row(__('WP Cron disabled', 'wp-seo-next'), !empty($report['wp']['wp_cron_disabled']) ? __('Yes', 'wp-seo-next') : __('No', 'wp-seo-next'));
        $this->row(__('PHP', 'wp-seo-next'), (string) ($report['php']['version'] ?? ''));
        $this->row(__('Memory limit', 'wp-seo-next'), (string) ($report['php']['memory_limit'] ?? ''));
        $this->row(__('Max execution time', 'wp-seo-next'), (string) ($report['php']['max_execution_time'] ?? ''));
        $this->row(__('Upload max filesize', 'wp-seo-next'), (string) ($report['php']['upload_max_filesize'] ?? ''));
        echo '</tbody>';
        echo '</table>';

        // Plugin summary.
        echo '<h2>' . esc_html__('WP SEO Next', 'wp-seo-next') . '</h2>';
        echo '<table class="widefat striped">';
        echo '<tbody>';
        $this->row(__('Plugin version', 'wp-seo-next'), (string) ($report['wpsn']['version'] ?? ''));
        $this->row(__('Local-only mode', 'wp-seo-next'), !empty($report['wpsn']['privacy_local_only']) ? __('Enabled', 'wp-seo-next') : __('Disabled', 'wp-seo-next'));
        $this->row(__('OpenAI configured', 'wp-seo-next'), !empty($report['features']['openai_configured']) ? __('Yes', 'wp-seo-next') : __('No', 'wp-seo-next'));
        $this->row(__('Search Console configured', 'wp-seo-next'), !empty($report['features']['gsc_configured']) ? __('Yes', 'wp-seo-next') : __('No', 'wp-seo-next'));
        $this->row(__('IndexNow key present', 'wp-seo-next'), !empty($report['features']['indexnow_configured']) ? __('Yes', 'wp-seo-next') : __('No', 'wp-seo-next'));
        $this->row(__('Enabled modules', 'wp-seo-next'), (string) ($report['wpsn']['modules_enabled_count'] ?? '0'));
        echo '</tbody>';
        echo '</table>';

        // Queue snapshot.
        echo '<h2>' . esc_html__('Queue & performance snapshot', 'wp-seo-next') . '</h2>';
        echo '<table class="widefat striped">';
        echo '<tbody>';
        $this->row(__('Queue mode', 'wp-seo-next'), (string) ($report['queue']['mode'] ?? ''));
        $this->row(__('Queue interval (sec)', 'wp-seo-next'), (string) ($report['queue']['interval_seconds'] ?? ''));
        $this->row(__('Max jobs per run', 'wp-seo-next'), (string) ($report['queue']['max_jobs_per_run'] ?? ''));

        $counts = isset($report['queue']['counts']) && is_array($report['queue']['counts']) ? $report['queue']['counts'] : [];
        foreach (['pending', 'running', 'done', 'failed'] as $k) {
            if (!array_key_exists($k, $counts)) {
                continue;
            }
            $this->row(sprintf(__('Jobs: %s', 'wp-seo-next'), $k), (string) ((int) $counts[$k]));
        }
        echo '</tbody>';
        echo '</table>';

        // DB snapshot.
        $db = isset($report['db']) && is_array($report['db']) ? $report['db'] : [];
        $tables = isset($db['tables']) && is_array($db['tables']) ? $db['tables'] : [];
        $totalBytes = (int) ($db['total_bytes'] ?? 0);
        $largest = isset($db['largest_table']) && is_array($db['largest_table']) ? $db['largest_table'] : [];
        $largestName = isset($largest['name']) ? (string) $largest['name'] : '';
        $largestBytes = (int) ($largest['bytes'] ?? 0);

        $fmt = static function (int $bytes): string {
            if ($bytes <= 0) {
                return '0 MB';
            }
            $mb = $bytes / 1024 / 1024;
            if ($mb >= 1024) {
                return round($mb / 1024, 2) . ' GB';
            }
            return round($mb, 2) . ' MB';
        };

        echo '<h2>' . esc_html__('Database usage (WPSN tables)', 'wp-seo-next') . '</h2>';
        echo '<p class="description">' . esc_html__('Row counts are approximate (InnoDB) and intended for performance budgeting.', 'wp-seo-next') . '</p>';
        echo '<table class="widefat striped">';
        echo '<thead><tr><th>' . esc_html__('Table', 'wp-seo-next') . '</th><th>' . esc_html__('Rows', 'wp-seo-next') . '</th><th>' . esc_html__('Size', 'wp-seo-next') . '</th></tr></thead><tbody>';
        foreach ($tables as $t) {
            if (!is_array($t)) {
                continue;
            }
            $name = isset($t['name']) ? (string) $t['name'] : '';
            if ($name === '') {
                continue;
            }
            $exists = !empty($t['exists']);
            $rows = isset($t['rows']) ? (int) $t['rows'] : 0;
            $bytes = isset($t['bytes']) ? (int) $t['bytes'] : 0;
            echo '<tr>';
            echo '<td><code>' . esc_html($name) . '</code>' . (!$exists ? ' <span style="color:#666;">(' . esc_html__('missing', 'wp-seo-next') . ')</span>' : '') . '</td>';
            echo '<td>' . ($exists ? esc_html((string) $rows) : '—') . '</td>';
            echo '<td>' . ($exists ? esc_html($fmt($bytes)) : '—') . '</td>';
            echo '</tr>';
        }
        echo '</tbody>';
        echo '<tfoot><tr>';
        echo '<th colspan="3" style="text-align:left;">' . esc_html__('Total', 'wp-seo-next') . ': ' . esc_html($fmt($totalBytes)) . ' · ' . esc_html__('Largest', 'wp-seo-next') . ': ' . esc_html($largestName !== '' ? $largestName : '—') . ' (' . esc_html($fmt($largestBytes)) . ')</th>';
        echo '</tr></tfoot>';
        echo '</table>';

        // Cron snapshot.
        $cron = isset($report['cron']) && is_array($report['cron']) ? $report['cron'] : [];
        $events = isset($cron['wpsn_events']) && is_array($cron['wpsn_events']) ? $cron['wpsn_events'] : [];
        echo '<h2>' . esc_html__('Scheduled WP-Cron events (wpsn_*)', 'wp-seo-next') . '</h2>';
        if (empty($events)) {
            echo '<p>' . esc_html__('No scheduled events found for WP SEO Next.', 'wp-seo-next') . '</p>';
        } else {
            echo '<table class="widefat striped">';
            echo '<thead><tr><th>' . esc_html__('Hook', 'wp-seo-next') . '</th><th>' . esc_html__('Next run (UTC)', 'wp-seo-next') . '</th><th>' . esc_html__('Schedule', 'wp-seo-next') . '</th></tr></thead><tbody>';
            foreach ($events as $e) {
                if (!is_array($e)) {
                    continue;
                }
                $hook = isset($e['hook']) ? (string) $e['hook'] : '';
                if ($hook === '') {
                    continue;
                }
                $next = isset($e['next_run_utc']) ? (string) $e['next_run_utc'] : '';
                $sched = isset($e['schedule']) ? (string) $e['schedule'] : '';
                echo '<tr>';
                echo '<td><code>' . esc_html($hook) . '</code></td>';
                echo '<td>' . esc_html($next !== '' ? $next : '—') . '</td>';
                echo '<td>' . esc_html($sched !== '' ? $sched : '—') . '</td>';
                echo '</tr>';
            }
            echo '</tbody></table>';
        }

        // Integrations.
        echo '<h2>' . esc_html__('Key integrations', 'wp-seo-next') . '</h2>';
        echo '<table class="widefat striped">';
        echo '<thead><tr>';
        echo '<th>' . esc_html__('Integration', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('Detected', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('WPSN module', 'wp-seo-next') . '</th>';
        echo '</tr></thead><tbody>';

        $ints = isset($report['integrations']) && is_array($report['integrations']) ? $report['integrations'] : [];

        $this->integrationRow($ints, 'elementor', 'Elementor');
        $this->integrationRow($ints, 'divi', 'Divi');
        $this->integrationRow($ints, 'beaver_builder', 'Beaver Builder');
        $this->integrationRow($ints, 'wpbakery', 'WPBakery');
        $this->integrationRow($ints, 'acf', 'ACF');
        $this->integrationRow($ints, 'meta_box', 'Meta Box');
        $this->integrationRow($ints, 'jetengine', 'JetEngine');
        $this->integrationRow($ints, 'woocommerce', 'WooCommerce', 'module_enabled');
        $this->integrationRow($ints, 'wpml', 'WPML', null);
        $this->integrationRow($ints, 'polylang', 'Polylang', null);

        echo '</tbody></table>';

        // Page builder integrations self-check + repair.
        echo '<h2>' . esc_html__('Page builder integrations: self-check', 'wp-seo-next') . '</h2>';
        echo '<p class="description">' . esc_html__('If SEO fields/panels are missing inside your builder, you can run a safe repair. This only updates WP SEO Next settings (it does not modify the builder plugin).', 'wp-seo-next') . '</p>';

        $modules = $this->container->get('modules');
        $pbEnabled = $modules->isEnabled('page_builders');
        $restEnabled = (bool) $settings->get('automation.rest.enabled', true);

        $repairUrl = wp_nonce_url(
            admin_url('admin-post.php?action=wpsn_diagnostics_builders_repair'),
            'wpsn_diagnostics_builders_repair'
        );

        echo '<p>';
        echo '<a class="button" href="' . esc_url($repairUrl) . '">' . esc_html__('Repair builder integrations', 'wp-seo-next') . '</a>';
        if (!$pbEnabled) {
            echo ' <span style="margin-left:8px; color:#b32d2e; font-weight:600;">' . esc_html__('Note: Page Builders module is currently disabled.', 'wp-seo-next') . '</span>';
        }
        if (!$restEnabled) {
            echo ' <span style="margin-left:8px; color:#b32d2e; font-weight:600;">' . esc_html__('Note: Automation REST is disabled (Universal Metabox needs it).', 'wp-seo-next') . '</span>';
        }
        echo '</p>';

        echo '<table class="widefat striped" style="max-width: 1100px;">';
        echo '<thead><tr>';
        echo '<th>' . esc_html__('Builder', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('Detected', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('WPSN setting', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('Universal Metabox', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('Needs REST', 'wp-seo-next') . '</th>';
        echo '</tr></thead><tbody>';

        // Elementor
        $elDetected = !empty($ints['elementor']['detected']);
        $elOn = (bool) $settings->get('integrations.elementor.enabled', true);
        $elCtrl = (bool) $settings->get('integrations.elementor.editor_controls', true);
        echo '<tr>';
        echo '<td><strong>Elementor</strong></td>';
        echo '<td>' . ($elDetected ? '<span style="color:#0a7; font-weight:600;">yes</span>' : '<span style="color:#666;">no</span>') . '</td>';
        echo '<td>' . ($elOn ? '<span style="color:#0a7; font-weight:600;">enabled</span>' : '<span style="color:#b32d2e; font-weight:600;">disabled</span>') . '<br /><span style="color:#666;">editor_controls: ' . ($elCtrl ? 'on' : 'off') . '</span></td>';
        echo '<td><span style="color:#666;">n/a</span></td>';
        echo '<td><span style="color:#666;">no</span></td>';
        echo '</tr>';

        // Divi
        $dvDetected = !empty($ints['divi']['detected']);
        $dvOn = (bool) $settings->get('integrations.divi.enabled', true);
        $dvUM = (bool) $settings->get('integrations.divi.universal_metabox', true);
        echo '<tr>';
        echo '<td><strong>Divi</strong></td>';
        echo '<td>' . ($dvDetected ? '<span style="color:#0a7; font-weight:600;">yes</span>' : '<span style="color:#666;">no</span>') . '</td>';
        echo '<td>' . ($dvOn ? '<span style="color:#0a7; font-weight:600;">enabled</span>' : '<span style="color:#b32d2e; font-weight:600;">disabled</span>') . '</td>';
        echo '<td>' . ($dvUM ? '<span style="color:#0a7; font-weight:600;">on</span>' : '<span style="color:#b32d2e; font-weight:600;">off</span>') . '</td>';
        echo '<td>' . ($dvUM ? ($restEnabled ? '<span style="color:#0a7; font-weight:600;">yes (OK)</span>' : '<span style="color:#b32d2e; font-weight:600;">yes (REST OFF)</span>') : '<span style="color:#666;">no</span>') . '</td>';
        echo '</tr>';

        // Beaver Builder
        $bbDetected = !empty($ints['beaver_builder']['detected']);
        $bbOn = (bool) $settings->get('integrations.beaver.enabled', true);
        $bbUM = (bool) $settings->get('integrations.beaver.universal_metabox', true);
        echo '<tr>';
        echo '<td><strong>Beaver Builder</strong></td>';
        echo '<td>' . ($bbDetected ? '<span style="color:#0a7; font-weight:600;">yes</span>' : '<span style="color:#666;">no</span>') . '</td>';
        echo '<td>' . ($bbOn ? '<span style="color:#0a7; font-weight:600;">enabled</span>' : '<span style="color:#b32d2e; font-weight:600;">disabled</span>') . '</td>';
        echo '<td>' . ($bbUM ? '<span style="color:#0a7; font-weight:600;">on</span>' : '<span style="color:#b32d2e; font-weight:600;">off</span>') . '</td>';
        echo '<td>' . ($bbUM ? ($restEnabled ? '<span style="color:#0a7; font-weight:600;">yes (OK)</span>' : '<span style="color:#b32d2e; font-weight:600;">yes (REST OFF)</span>') : '<span style="color:#666;">no</span>') . '</td>';
        echo '</tr>';

        echo '</tbody></table>';

        // Enabled modules list.
        $mods = isset($report['wpsn']['modules_enabled']) && is_array($report['wpsn']['modules_enabled']) ? $report['wpsn']['modules_enabled'] : [];
        echo '<h2>' . esc_html__('Enabled modules', 'wp-seo-next') . '</h2>';
        if (empty($mods)) {
            echo '<p>' . esc_html__('No enabled modules found (unexpected).', 'wp-seo-next') . '</p>';
        } else {
            echo '<ul style="columns:2; max-width: 900px;">';
            foreach ($mods as $m) {
                if (!is_array($m)) {
                    continue;
                }
                $name = isset($m['name']) ? (string) $m['name'] : '';
                $id = isset($m['id']) ? (string) $m['id'] : '';
                if ($id === '' && $name === '') {
                    continue;
                }
                echo '<li><strong>' . esc_html($name !== '' ? $name : $id) . '</strong> <span style="color:#666;">(' . esc_html($id) . ')</span></li>';
            }
            echo '</ul>';
        }

        // HTTP circuit breakers snapshot.
        echo '<h2>' . esc_html__('HTTP health: circuit breakers', 'wp-seo-next') . '</h2>';
        echo '<p class="description">' . esc_html__('When an external service keeps failing (503/429/timeouts), WP SEO Next opens a short circuit to avoid request storms. You can inspect and reset the circuits below.', 'wp-seo-next') . '</p>';

        $cbKeys = CircuitBreaker::registry();
        if (empty($cbKeys)) {
            echo '<p>' . esc_html__('No circuit breaker entries yet.', 'wp-seo-next') . '</p>';
        } else {
            $clearAllUrl = admin_url('admin-post.php?action=wpsn_diagnostics_clear_http_circuits');

            echo '<form method="post" action="' . esc_url($clearAllUrl) . '">';
            wp_nonce_field('wpsn_diagnostics_clear_http_circuits', 'wpsn_nonce');
            echo '<p><button type="submit" class="button">' . esc_html__('Clear all circuits', 'wp-seo-next') . '</button></p>';
            echo '</form>';

            echo '<table class="widefat striped" style="max-width: 1100px;">';
            echo '<thead><tr>';
            echo '<th>' . esc_html__('Key', 'wp-seo-next') . '</th>';
            echo '<th>' . esc_html__('State', 'wp-seo-next') . '</th>';
            echo '<th>' . esc_html__('Fails', 'wp-seo-next') . '</th>';
            echo '<th>' . esc_html__('Open until', 'wp-seo-next') . '</th>';
            echo '<th>' . esc_html__('Last status', 'wp-seo-next') . '</th>';
            echo '<th>' . esc_html__('Last error', 'wp-seo-next') . '</th>';
            echo '<th>' . esc_html__('Action', 'wp-seo-next') . '</th>';
            echo '</tr></thead><tbody>';

            $now = time();
            foreach ($cbKeys as $k) {
                $st = CircuitBreaker::getStateForKey($k);
                $fails = isset($st['fails']) ? (int) $st['fails'] : 0;
                $openUntil = isset($st['open_until']) ? (int) $st['open_until'] : 0;
                $isOpen = $openUntil > $now;
                $lastStatus = isset($st['last_status']) ? (int) $st['last_status'] : 0;
                $lastErr = isset($st['last_error']) ? (string) $st['last_error'] : '';
                $stateLabel = $isOpen ? ('OPEN (' . max(1, $openUntil - $now) . 's)') : 'closed';
                $openUntilStr = $openUntil > 0 ? date_i18n('Y-m-d H:i:s', $openUntil) : '—';

                echo '<tr>';
                echo '<td><code>' . esc_html($k) . '</code></td>';
                echo '<td>' . ($isOpen ? '<span style="color:#b32d2e; font-weight:600;">' . esc_html($stateLabel) . '</span>' : '<span style="color:#0a7; font-weight:600;">' . esc_html($stateLabel) . '</span>') . '</td>';
                echo '<td>' . esc_html((string) $fails) . '</td>';
                echo '<td>' . esc_html($openUntilStr) . '</td>';
                echo '<td>' . esc_html($lastStatus > 0 ? (string) $lastStatus : '—') . '</td>';
                echo '<td>' . esc_html($lastErr !== '' ? $lastErr : '—') . '</td>';
                echo '<td>';
                $clearUrl = admin_url('admin-post.php?action=wpsn_diagnostics_clear_http_circuit');
                echo '<form method="post" action="' . esc_url($clearUrl) . '" style="margin:0;">';
                wp_nonce_field('wpsn_diagnostics_clear_http_circuit', 'wpsn_nonce');
                echo '<input type="hidden" name="key" value="' . esc_attr($k) . '" />';
                echo '<button type="submit" class="button button-small">' . esc_html__('Clear', 'wp-seo-next') . '</button>';
                echo '</form>';
                echo '</td>';
                echo '</tr>';
            }

            echo '</tbody></table>';
        }

        // Raw JSON preview (collapsible).
        $json = wp_json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        echo '<hr />';
        echo '<details style="max-width: 1100px;">';
        echo '<summary><strong>' . esc_html__('Raw JSON preview', 'wp-seo-next') . '</strong></summary>';
        echo '<p class="description">' . esc_html__('This preview is the same data as the downloaded report.', 'wp-seo-next') . '</p>';
        echo '<textarea readonly style="width:100%; min-height: 320px; font-family: ui-monospace, Menlo, Monaco, Consolas, monospace;">' . esc_textarea((string) $json) . '</textarea>';
        echo '</details>';

        echo '</div>';
    }

    private function row(string $label, string $value): void
    {
        echo '<tr><th style="width:280px;">' . esc_html($label) . '</th><td>' . esc_html($value) . '</td></tr>';
    }

    /**
     * @param array<string,mixed> $integrations
     */
    private function integrationRow(array $integrations, string $key, string $label, ?string $moduleKey = 'integration_module_enabled'): void
    {
        $data = isset($integrations[$key]) && is_array($integrations[$key]) ? $integrations[$key] : [];

        $detected = !empty($data['detected']);

        $moduleStatus = '';
        if ($moduleKey === null) {
            $moduleStatus = '—';
        } else {
            $moduleStatus = !empty($data[$moduleKey]) ? __('Enabled', 'wp-seo-next') : __('Disabled', 'wp-seo-next');
        }

        echo '<tr>';
        echo '<td>' . esc_html($label) . '</td>';
        echo '<td>' . ($detected ? '<span style="color: #0a7; font-weight:600;">' . esc_html__('Yes', 'wp-seo-next') . '</span>' : '<span style="color:#999;">' . esc_html__('No', 'wp-seo-next') . '</span>') . '</td>';
        echo '<td>' . esc_html($moduleStatus) . '</td>';
        echo '</tr>';
    }

    public function handleExport(): void
    {
        if (!current_user_can(Capabilities::CAP_TOOLS)) {
            wp_die(esc_html__('You do not have permission to do this action.', 'wp-seo-next'));
        }

        check_admin_referer('wpsn_diagnostics_export');

        $report = $this->buildReport();
        $json = wp_json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);

        $filename = 'wpsn-diagnostics-' . gmdate('Ymd-His') . '.json';

        nocache_headers();
        header('Content-Type: application/json; charset=utf-8');
        header('Content-Disposition: attachment; filename=' . $filename);
        echo (string) $json;
        exit;
    }
    public function handleUpdateModes(): void
    {
        if (!current_user_can(Capabilities::CAP_TOOLS)) {
            $url = $this->pageUrl(['wpsn_diag_notice' => 'permission']);
            wp_safe_redirect($url);
            exit;
        }

        check_admin_referer('wpsn_diagnostics_update_modes', 'wpsn_nonce');

        $repo = $this->container->get('settings_repo');
        $current = $repo->getAll();

        // Update requested flags.
        $current['compatibility']['safe_mode'] = !empty($_POST['compatibility_safe_mode']);
        $current['compatibility']['disable_output'] = !empty($_POST['compatibility_disable_output']);
        $current['compatibility']['auto_disable_output_on_conflict'] = !empty($_POST['compatibility_auto_disable_output_on_conflict']);

        $current['performance']['admin']['minimize_admin_footprint'] = !empty($_POST['performance_minimize_admin_footprint']);
        $current['performance']['admin']['ajax_enabled'] = !empty($_POST['performance_admin_ajax_enabled']);
        $current['performance']['admin']['ajax_lite_boot'] = !empty($_POST['performance_admin_ajax_lite_boot']);
        $current['performance']['admin']['collect_metrics'] = !empty($_POST['performance_collect_metrics']);
        $current['performance']['admin']['record_history'] = !empty($_POST['performance_record_history']);

        $current['performance']['frontend']['contract_enabled'] = !empty($_POST['performance_frontend_contract']);
        $current['performance']['frontend']['inspector_on_demand'] = !empty($_POST['performance_frontend_inspector_on_demand']);

        $repo->update($current);

        // Flush runtime cache.
        $this->container->get('settings')->flush();

        $url = $this->pageUrl(['wpsn_diag_notice' => 'modes_saved']);
        wp_safe_redirect($url);
        exit;
    }

    public function handleBuildersRepair(): void
    {
        if (!current_user_can(Capabilities::CAP_TOOLS)) {
            $url = $this->pageUrl(['wpsn_diag_notice' => 'permission']);
            wp_safe_redirect($url);
            exit;
        }

        check_admin_referer('wpsn_diagnostics_builders_repair');

        $repo = $this->container->get('settings_repo');
        $current = $repo->getAll();

        // Detect integrations at runtime (safe).
        $report = $this->buildReport();
        $ints = isset($report['integrations']) && is_array($report['integrations']) ? $report['integrations'] : [];

        // Always ensure the module itself is enabled.
        $current['modules']['page_builders'] = true;

        // Elementor
        if (!empty($ints['elementor']['detected'])) {
            $current['integrations']['elementor']['enabled'] = true;
            $current['integrations']['elementor']['editor_controls'] = true;
        }

        // Divi
        if (!empty($ints['divi']['detected'])) {
            $current['integrations']['divi']['enabled'] = true;
            $current['integrations']['divi']['universal_metabox'] = true;
            $current['automation']['rest']['enabled'] = true;
        }

        // Beaver
        if (!empty($ints['beaver_builder']['detected'])) {
            $current['integrations']['beaver']['enabled'] = true;
            $current['integrations']['beaver']['universal_metabox'] = true;
            $current['automation']['rest']['enabled'] = true;
        }

        $repo->update($current);
        $this->container->get('settings')->flush();

        $url = $this->pageUrl(['wpsn_diag_notice' => 'builders_repaired']);
        wp_safe_redirect($url);
        exit;
    }

    public function handleSupportBundle(): void
    {
        if (!current_user_can(Capabilities::CAP_TOOLS)) {
            wp_die(esc_html__('You do not have permission to do this action.', 'wp-seo-next'));
        }

        check_admin_referer('wpsn_diagnostics_support_bundle');

        $bundle = (new SupportBundleBuilder($this->container))->build();
        $json = wp_json_encode($bundle, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);

        $filename = 'wpsn-support-bundle-' . gmdate('Ymd-His') . '.json';

        nocache_headers();
        header('Content-Type: application/json; charset=utf-8');
        header('Content-Disposition: attachment; filename=' . $filename);
        header('X-Content-Type-Options: nosniff');
        echo (string) $json;
        exit;
    }




public function handleRecoveryHelperInstall(): void
{
    if (!current_user_can(Capabilities::CAP_TOOLS)) {
        $url = $this->pageUrl(['wpsn_diag_notice' => 'permission']);
        wp_safe_redirect($url);
        exit;
    }

    check_admin_referer('wpsn_recovery_helper_install', 'wpsn_nonce');

    $res = RecoveryHelper::install();

    $url = $this->pageUrl([
        'wpsn_diag_notice' => $res['ok'] ? 'recovery_installed' : 'recovery_failed',
        'wpsn_diag_msg' => rawurlencode($res['message']),
    ]);
    wp_safe_redirect($url);
    exit;
}

public function handleRecoveryHelperUninstall(): void
{
    if (!current_user_can(Capabilities::CAP_TOOLS)) {
        $url = $this->pageUrl(['wpsn_diag_notice' => 'permission']);
        wp_safe_redirect($url);
        exit;
    }

    check_admin_referer('wpsn_recovery_helper_uninstall', 'wpsn_nonce');

    $res = RecoveryHelper::uninstall();

    $url = $this->pageUrl([
        'wpsn_diag_notice' => $res['ok'] ? 'recovery_removed' : 'recovery_failed',
        'wpsn_diag_msg' => rawurlencode($res['message']),
    ]);
    wp_safe_redirect($url);
    exit;
}

public function handleClearFatalLog(): void
{
    if (!current_user_can(Capabilities::CAP_TOOLS)) {
        $url = $this->pageUrl(['wpsn_diag_notice' => 'permission']);
        wp_safe_redirect($url);
        exit;
    }

    check_admin_referer('wpsn_diagnostics_clear_fatal_log', 'wpsn_nonce');

    if (function_exists('delete_option')) {
        delete_option('wpsn_fatal_log');
    }

    $url = $this->pageUrl(['wpsn_diag_notice' => 'fatal_cleared']);
    wp_safe_redirect($url);
    exit;
}

public function handleClearPerfHistory(): void
{
    if (!current_user_can(Capabilities::CAP_TOOLS)) {
        $url = $this->pageUrl(['wpsn_diag_notice' => 'permission']);
        wp_safe_redirect($url);
        exit;
    }

    check_admin_referer('wpsn_diagnostics_clear_perf_history', 'wpsn_nonce');

    \WPSN\Core\PerfHistory::clear();

    $url = $this->pageUrl(['wpsn_diag_notice' => 'perf_cleared']);
    wp_safe_redirect($url);
    exit;
}

public function handleClearHttpCircuit(): void
{
    if (!current_user_can(Capabilities::CAP_TOOLS)) {
        $url = $this->pageUrl(['wpsn_diag_notice' => 'permission']);
        wp_safe_redirect($url);
        exit;
    }

    check_admin_referer('wpsn_diagnostics_clear_http_circuit', 'wpsn_nonce');

    $key = isset($_REQUEST['key']) ? sanitize_key((string) $_REQUEST['key']) : '';
    if ($key !== '') {
        $known = CircuitBreaker::registry();
        if (in_array($key, $known, true)) {
            CircuitBreaker::clear($key);
        }
    }

    $url = $this->pageUrl(['wpsn_diag_notice' => 'http_circuit_cleared']);
    wp_safe_redirect($url);
    exit;
}

public function handleClearHttpCircuits(): void
{
    if (!current_user_can(Capabilities::CAP_TOOLS)) {
        $url = $this->pageUrl(['wpsn_diag_notice' => 'permission']);
        wp_safe_redirect($url);
        exit;
    }

    check_admin_referer('wpsn_diagnostics_clear_http_circuits', 'wpsn_nonce');

    $keys = CircuitBreaker::registry();
    foreach ($keys as $k) {
        CircuitBreaker::clear($k);
    }

    $url = $this->pageUrl(['wpsn_diag_notice' => 'http_circuits_cleared']);
    wp_safe_redirect($url);
    exit;
}

}
