<?php

namespace WPSN\Core;

defined('ABSPATH') || exit;

/**
 * Lightweight persistent performance history (opt-in).
 *
 * Purpose:
 * - help spot regressions without installing profiling plugins
 * - keep overhead close to zero when disabled
 *
 * Notes:
 * - records only WP SEO Next admin pages (page=wpsn* / wp-seo-next)
 * - stores a small ring buffer in a non-autoloaded option
 */
final class PerfHistory
{
    private const OPTION_KEY = 'wpsn_perf_history';
    private const MAX_ITEMS  = 50;

    private static bool $hooked = false;

    public static function init(Settings $settings): void
    {
        if (self::$hooked) {
            return;
        }
        self::$hooked = true;

        // Hard gate: do nothing unless the probe itself is enabled.
        if (!(bool) $settings->get('performance.admin.collect_metrics', false)) {
            return;
        }

        // Opt-in: recording history is a separate toggle.
        if (!(bool) $settings->get('performance.admin.record_history', false)) {
            return;
        }

        add_action('shutdown', static function (): void {
            if (!is_admin()) {
                return;
            }

            if (!self::isWpsnAdminContext()) {
                return;
            }

            $snap = PerfProbe::snapshot();
            if (empty($snap) || empty($snap['enabled'])) {
                return;
            }

            $context = [
                'at_utc' => gmdate('c'),
                'page' => isset($_GET['page']) ? sanitize_key((string) wp_unslash($_GET['page'])) : '',
                'screen_base' => '',
                'request_uri' => isset($_SERVER['REQUEST_URI']) ? substr((string) $_SERVER['REQUEST_URI'], 0, 220) : '',
            ];

            if (function_exists('get_current_screen')) {
                $screen = get_current_screen();
                if (is_object($screen) && isset($screen->base)) {
                    $context['screen_base'] = sanitize_key((string) $screen->base);
                }
            }

            self::record($snap, $context);
        }, 9999);
    }

    /**
     * @param array<string,mixed> $snapshot
     * @param array<string,mixed> $context
     */
    public static function record(array $snapshot, array $context = []): void
    {
        if (!function_exists('get_option') || !function_exists('update_option')) {
            return;
        }

        $items = get_option(self::OPTION_KEY, []);
        if (!is_array($items)) {
            $items = [];
        }

        $row = [
            'at_utc' => isset($context['at_utc']) ? sanitize_text_field((string) $context['at_utc']) : gmdate('c'),
            'page' => isset($context['page']) ? sanitize_key((string) $context['page']) : '',
            'screen_base' => isset($context['screen_base']) ? sanitize_key((string) $context['screen_base']) : '',
            'request_uri' => isset($context['request_uri']) ? sanitize_text_field((string) $context['request_uri']) : '',
            'total_ms' => isset($snapshot['total_ms']) ? (int) $snapshot['total_ms'] : 0,
            'queries' => isset($snapshot['queries']) ? (int) $snapshot['queries'] : 0,
            'memory_peak_bytes' => isset($snapshot['memory_peak_bytes']) ? (int) $snapshot['memory_peak_bytes'] : 0,
            'metrics_ms' => [],
        ];

        if (isset($snapshot['metrics_ms']) && is_array($snapshot['metrics_ms'])) {
            $metrics = $snapshot['metrics_ms'];
            // Keep only top 20 metrics to avoid storing large arrays.
            arsort($metrics);
            $trim = [];
            $i = 0;
            foreach ($metrics as $k => $v) {
                $k = sanitize_key((string) $k);
                if ($k === '') {
                    continue;
                }
                $trim[$k] = (float) $v;
                $i++;
                if ($i >= 20) {
                    break;
                }
            }
            $row['metrics_ms'] = $trim;
        }

        // Newest first.
        array_unshift($items, $row);

        if (count($items) > self::MAX_ITEMS) {
            $items = array_slice($items, 0, self::MAX_ITEMS);
        }

        // Keep it non-autoloaded.
        update_option(self::OPTION_KEY, $items, false);
    }

    /**
     * @return array<int,array<string,mixed>>
     */
    public static function all(): array
    {
        if (!function_exists('get_option')) {
            return [];
        }
        $items = get_option(self::OPTION_KEY, []);
        return is_array($items) ? $items : [];
    }

    public static function clear(): void
    {
        if (!function_exists('delete_option')) {
            return;
        }
        delete_option(self::OPTION_KEY);
    }

    private static function isWpsnAdminContext(): bool
    {
        $page = isset($_GET['page']) ? sanitize_key((string) wp_unslash($_GET['page'])) : '';
        if ($page === '') {
            return false;
        }

        if ($page === 'wp-seo-next' || $page === 'wpsn') {
            return true;
        }

        return (strpos($page, 'wpsn-') === 0);
    }
}
