<?php

namespace WPSN\Modules\Diagnostics;

use WPSN\Core\ModuleRegistry;
use WPSN\Core\Settings;
use WPSN\Core\Queue\QueueInterface;
use WPSN\Core\CompatibilityDetector;
use WPSN\Core\PerfProbe;
use WPSN\Modules\PageBuilders\BuilderDetector;

defined('ABSPATH') || exit;

final class DiagnosticsReportBuilder
{
    private Settings $settings;
    private ModuleRegistry $modules;
    private QueueInterface $queue;

    public function __construct(Settings $settings, ModuleRegistry $modules, QueueInterface $queue)
    {
        $this->settings = $settings;
        $this->modules = $modules;
        $this->queue = $queue;
    }

    /**
     * Build a safe diagnostic report.
     *
     * IMPORTANT: Do not include secrets (tokens/keys).
     *
     * @return array<string,mixed>
     */
    public function build(): array
    {
        global $wp_version;

        $home = home_url('/');
        $home = is_string($home) ? $home : '';

        $site = site_url('/');
        $site = is_string($site) ? $site : '';

        // Compatibility: detect other SEO plugins and compute effective output-disable state.
        $seoPlugins = CompatibilityDetector::detectSeoPlugins();
        $hasSeoConflict = false;
        foreach ($seoPlugins as $row) {
            if (is_array($row) && !empty($row['detected'])) {
                $hasSeoConflict = true;
                break;
            }
        }

        $autoDisableOnConflict = (bool) $this->settings->get('compatibility.auto_disable_output_on_conflict', false);
        $disableOutputStored = (bool) $this->settings->get('compatibility.disable_output', false);
        $disableOutputConst = (defined('WPSN_DISABLE_OUTPUT') && (bool) WPSN_DISABLE_OUTPUT);
        $disableOutputEffective = $disableOutputConst || $disableOutputStored || ($autoDisableOnConflict && $hasSeoConflict);

        $report = [
            'generated_at' => gmdate('c'),
            'site' => [
                'home_url' => $home,
                'site_url' => $site,
                'is_ssl' => is_ssl(),
                'locale' => (string) get_locale(),
                'multisite' => is_multisite(),
            ],
            'wp' => [
                'version' => is_string($wp_version) ? $wp_version : (string) ($wp_version ?? ''),
                'environment_type' => function_exists('wp_get_environment_type') ? (string) wp_get_environment_type() : '',
                'wp_cron_disabled' => defined('DISABLE_WP_CRON') && DISABLE_WP_CRON,
                'object_cache' => function_exists('wp_using_ext_object_cache') ? (bool) wp_using_ext_object_cache() : false,
            ],
            'php' => [
                'version' => PHP_VERSION,
                'memory_limit' => (string) ini_get('memory_limit'),
                'max_execution_time' => (int) ini_get('max_execution_time'),
                'post_max_size' => (string) ini_get('post_max_size'),
                'upload_max_filesize' => (string) ini_get('upload_max_filesize'),
            ],
            'wpsn' => [
                'version' => defined('WPSN_VERSION') ? (string) WPSN_VERSION : '',
                'privacy_local_only' => (bool) $this->settings->get('privacy.local_only', false),
                'modules_enabled' => $this->enabledModules(),
                'modules_enabled_count' => count($this->enabledModules()),
            ],
            'queue' => [
                'mode' => (string) $this->settings->get('performance.queue.mode', 'manual'),
                'interval_seconds' => (int) ((int) $this->settings->get('performance.queue.interval_minutes', 5)) * 60,
                'max_jobs_per_run' => (int) $this->settings->get('performance.queue.max_jobs', 10),
                'counts' => $this->queue->counts(),
            'next_tick_utc' => ($t = wp_next_scheduled('wpsn_queue_tick')) ? gmdate('c', (int) $t) : null,
            ],
            'db' => $this->dbSnapshot(),
            'cron' => [
                'wpsn_events' => $this->cronSnapshot(),
            ],
            'integrations' => $this->integrations(),
            'compatibility' => [
                'safe_mode' => (defined('WPSN_SAFE_MODE') && (bool) WPSN_SAFE_MODE) || (bool) $this->settings->get('compatibility.safe_mode', false),
                // Effective flag (includes runtime safeguards).
                'disable_output' => $disableOutputEffective,
                // Stored values (for debugging / support).
                'disable_output_stored' => $disableOutputStored,
                'disable_output_forced_by_constant' => $disableOutputConst,
                'auto_disable_output_on_conflict' => $autoDisableOnConflict,
                'disable_output_forced_by_conflict' => $autoDisableOnConflict && $hasSeoConflict,
                'conflict_detected' => $hasSeoConflict,
                'other_seo_plugins' => $seoPlugins,
            ],
            'performance_probe' => PerfProbe::snapshot(),
            'features' => [
                'openai_configured' => $this->hasOpenAiKey(),
                'gsc_configured' => $this->hasGscProperty(),
                'indexnow_configured' => $this->hasIndexNowKey(),
            ],
        ];

        return $report;
    }

    /**
     * Lightweight DB snapshot for performance budgeting.
     *
     * @return array<string,mixed>
     */
    private function dbSnapshot(): array
    {
        global $wpdb;

        $tables = $this->pluginTables();
        $stats = [];

        $totalBytes = 0;
        $largest = ['name' => '', 'bytes' => 0];

        foreach ($tables as $table) {
            $row = $wpdb->get_row($wpdb->prepare('SHOW TABLE STATUS LIKE %s', $table), ARRAY_A);
            if (!is_array($row) || empty($row)) {
                $stats[] = [
                    'name' => $table,
                    'exists' => false,
                ];
                continue;
            }

            $bytes = (int) ($row['Data_length'] ?? 0) + (int) ($row['Index_length'] ?? 0);
            $rows = (int) ($row['Rows'] ?? 0);
            $engine = isset($row['Engine']) ? (string) $row['Engine'] : '';

            $stats[] = [
                'name' => $table,
                'exists' => true,
                'rows' => $rows,
                'bytes' => $bytes,
                'engine' => $engine,
            ];

            $totalBytes += $bytes;
            if ($bytes > (int) $largest['bytes']) {
                $largest = ['name' => $table, 'bytes' => $bytes];
            }
        }

        return [
            'tables' => $stats,
            'total_bytes' => $totalBytes,
            'largest_table' => $largest,
        ];
    }

    /**
     * @return array<int,array<string,mixed>>
     */
    private function cronSnapshot(): array
    {
        if (!function_exists('_get_cron_array')) {
            return [];
        }

        $cron = _get_cron_array();
        if (!is_array($cron) || empty($cron)) {
            return [];
        }

        $out = [];
        foreach ($cron as $ts => $hooks) {
            if (!is_array($hooks)) {
                continue;
            }
            foreach ($hooks as $hook => $events) {
                if (!is_string($hook) || strpos($hook, 'wpsn_') !== 0) {
                    continue;
                }
                if (!is_array($events)) {
                    continue;
                }
                foreach ($events as $sig => $event) {
                    if (!is_array($event)) {
                        continue;
                    }
                    $out[] = [
                        'hook' => $hook,
                        'next_run_utc' => gmdate('c', (int) $ts),
                        'schedule' => isset($event['schedule']) ? (string) $event['schedule'] : '',
                    ];
                }
            }
        }

        usort($out, static function ($a, $b): int {
            $ta = isset($a['next_run_utc']) ? (string) $a['next_run_utc'] : '';
            $tb = isset($b['next_run_utc']) ? (string) $b['next_run_utc'] : '';
            return strcmp($ta, $tb);
        });

        return array_slice($out, 0, 100);
    }

    /**
     * List of core plugin tables (best-effort; not all modules use custom tables).
     *
     * @return array<int,string>
     */
    private function pluginTables(): array
    {
        global $wpdb;

        $list = [
            // Queue
            $wpdb->prefix . 'wpsn_queue_jobs',

            // Activity log
            $wpdb->prefix . 'wpsn_activity_log',

            // Notifications
            $wpdb->prefix . 'wpsn_notifications',

            // Privacy + AI readiness
            $wpdb->prefix . 'wpsn_external_log',
            $wpdb->prefix . 'wpsn_policy_log',
            $wpdb->prefix . 'wpsn_ai_botblock_stats',

            // Audit
            $wpdb->prefix . 'wpsn_audit_scans',
            $wpdb->prefix . 'wpsn_audit_scan_issues',
            $wpdb->prefix . 'wpsn_audit_scan_titles',
            $wpdb->prefix . 'wpsn_audit_scan_descriptions',
            $wpdb->prefix . 'wpsn_audit_scan_title_keys',
            $wpdb->prefix . 'wpsn_audit_scan_description_keys',
            $wpdb->prefix . 'wpsn_audit_issues',

            // Schema validator
            $wpdb->prefix . 'wpsn_schema_scans',
            $wpdb->prefix . 'wpsn_schema_issues',

            // Search Console
            $wpdb->prefix . 'wpsn_gsc_pages',
            $wpdb->prefix . 'wpsn_gsc_query_pages',
            $wpdb->prefix . 'wpsn_gsc_daily_pages',
            $wpdb->prefix . 'wpsn_gsc_daily_query_pages',
            $wpdb->prefix . 'wpsn_gsc_alerts',

            // Internal linking
            $wpdb->prefix . 'wpsn_il_suggestions',
            $wpdb->prefix . 'wpsn_il_inlinks',

            // AI usage
            $wpdb->prefix . 'wpsn_ai_calls',
            $wpdb->prefix . 'wpsn_ai_credits_ledger',

            // IndexNow + redirects
            $wpdb->prefix . 'wpsn_indexnow_log',
            $wpdb->prefix . 'wpsn_redirects',
            $wpdb->prefix . 'wpsn_404_log',
            $wpdb->prefix . 'wpsn_redirect_migration_runs',
            $wpdb->prefix . 'wpsn_redirect_migration_items',

            // Config Sync
            $wpdb->prefix . 'wpsn_config_sync_log',
        ];

        return array_values(array_unique($list));
    }

    /**
     * @return array<int, array<string,mixed>>
     */
    private function enabledModules(): array
    {
        $out = [];
        foreach ($this->modules->all() as $id => $module) {
            $enabled = $this->modules->isEnabled($id);
            if (!$enabled) {
                continue;
            }
            $out[] = [
                'id' => (string) $id,
                'name' => (string) $module->name(),
            ];
        }
        return $out;
    }

    /**
     * @return array<string, array<string,mixed>>
     */
    private function integrations(): array
    {
        // We avoid listing all active plugins to reduce accidental oversharing.
        // Instead we focus on key integrations.

        $pageBuildersEnabled = $this->modules->isEnabled('page_builders');
        $customFieldsEnabled = $this->modules->isEnabled('custom_fields');

        $out = [
            'elementor' => [
                'detected' => BuilderDetector::hasElementor(),
                'integration_module_enabled' => $pageBuildersEnabled,
            ],
            'divi' => [
                'detected' => BuilderDetector::hasDivi(),
                'integration_module_enabled' => $pageBuildersEnabled,
            ],
            'beaver_builder' => [
                'detected' => BuilderDetector::hasBeaver(),
                'integration_module_enabled' => $pageBuildersEnabled,
            ],
            'wpbakery' => [
                'detected' => defined('WPB_VC_VERSION') || class_exists('Vc_Manager'),
                'integration_module_enabled' => $pageBuildersEnabled,
            ],
            'acf' => [
                'detected' => function_exists('get_field'),
                'integration_module_enabled' => $customFieldsEnabled,
            ],
            'meta_box' => [
                'detected' => function_exists('rwmb_meta'),
                'integration_module_enabled' => $customFieldsEnabled,
            ],
            'jetengine' => [
                'detected' => function_exists('jet_engine'),
                'integration_module_enabled' => $customFieldsEnabled,
            ],
            'woocommerce' => [
                'detected' => class_exists('WooCommerce') || function_exists('wc_get_product'),
                'module_enabled' => $this->modules->isEnabled('woocommerce'),
            ],
            'wpml' => [
                'detected' => defined('ICL_SITEPRESS_VERSION') || class_exists('SitePress'),
            ],
            'polylang' => [
                'detected' => function_exists('pll_current_language') || defined('POLYLANG_VERSION'),
            ],
        ];

        return $out;
    }

    private function hasOpenAiKey(): bool
    {
        // OpenAI key is stored outside the main settings export.
        if (class_exists('WPSN\\Modules\\AI\\AISecretsRepository')) {
            $repo = new \WPSN\Modules\AI\AISecretsRepository();
            return $repo->hasOpenAIKey();
        }
        return false;
    }

    private function hasGscProperty(): bool
    {
        $p = (string) $this->settings->get('search_console.property', '');
        $p = trim($p);
        return $p !== '';
    }

    private function hasIndexNowKey(): bool
    {
        // The key file is generated in Tools → IndexNow; we only report if a key exists.
        $key = (string) get_option('wpsn_indexnow_key', '');
        $key = trim($key);
        return $key !== '';
    }
}
