<?php
/**
 * Basic Security Score Module
 *
 * Provides a tier-based security score using risk-weighted scoring.
 * Features gate requirements that must be met to advance to higher tiers.
 *
 * @package     WPUltimateSecurity\UltimateSecurity\Modules\Monitoring
 * @since       2.1.0
 * @version     3.0.0
 */

declare(strict_types=1);

namespace WPUltimateSecurity\UltimateSecurity\Modules\Monitoring;

use WPUltimateSecurity\UltimateSecurity\Modules\Base\AbstractModule;
use WPUltimateSecurity\UltimateSecurity\Support\Helpers\Utils;

/**
 * Basic Security Score Module
 *
 * Implements a 5-tier security scoring system:
 * - Level 1: Vulnerable (0-19 points)
 * - Level 2: Basic (20-39 points, gate: SSL)
 * - Level 3: Protected (40-59 points, gates: SSL + MFA (any 2FA method or Passkeys) + Login Rate Limiting)
 * - Level 4: Hardened (60-79 points, gates: All Level 3 + CAPTCHA + Password Policy)
 * - Level 5: Fortress (80-100 points, gates: All Level 4 + Audit Logs + File Integrity)
 *
 * @since 2.1.0
 */
class BasicSecurityScore extends AbstractModule
{
    /**
     * Module version
     */
    protected const VERSION = '3.0.0';

    /**
     * Cache transient key
     */
    private const CACHE_KEY = 'ultimate_security_score_cache';

    /**
     * Cache duration in seconds (5 minutes)
     */
    private const CACHE_DURATION = 300;

    /**
     * Security check categories
     */
    private const CATEGORY_CRITICAL = 'critical';
    private const CATEGORY_HIGH = 'high';
    private const CATEGORY_MEDIUM = 'medium';
    private const CATEGORY_LOW = 'low';

    /**
     * Security checks with weighted points and tier gates
     *
     * Each check defines:
     * - key: Unique identifier
     * - name: Human-readable name
     * - points: Point value (Critical=15, High=10, Medium=5, Low=2)
     * - category: Risk category (critical, high, medium, low)
     * - gate_for_tier: Tier level this check is required for (null if not a gate)
     * - pro_only: Whether this requires the Pro version
     */
    private const SECURITY_CHECKS = [
        // Critical (15 points each)
        '2fa_enabled' => [
            'key' => '2fa_enabled',
            'name' => 'Two-Factor Authentication',
            'description' => 'Two-factor authentication adds an extra layer of security to user logins.',
            'points' => 15,
            'category' => self::CATEGORY_CRITICAL,
            'gate_for_tier' => 3,
            'pro_only' => false,
        ],
        'ssl_enabled' => [
            'key' => 'ssl_enabled',
            'name' => 'SSL/HTTPS',
            'description' => 'SSL encryption protects data transmitted between users and your site.',
            'points' => 15,
            'category' => self::CATEGORY_CRITICAL,
            'gate_for_tier' => 2,
            'pro_only' => false,
        ],
        'login_rate_limit' => [
            'key' => 'login_rate_limit',
            'name' => 'Login Rate Limiting',
            'description' => 'Limiting login attempts helps prevent brute force attacks.',
            'points' => 15,
            'category' => self::CATEGORY_CRITICAL,
            'gate_for_tier' => 3,
            'pro_only' => false,
        ],

        // High (10 points each)
        'captcha_enabled' => [
            'key' => 'captcha_enabled',
            'name' => 'CAPTCHA Protection',
            'description' => 'CAPTCHA prevents automated bot attacks on login forms.',
            'points' => 10,
            'category' => self::CATEGORY_HIGH,
            'gate_for_tier' => 4,
            'pro_only' => false,
        ],
        'password_policy' => [
            'key' => 'password_policy',
            'name' => 'Password Policy',
            'description' => 'Enforcing strong passwords helps prevent brute force attacks.',
            'points' => 10,
            'category' => self::CATEGORY_HIGH,
            'gate_for_tier' => 4,
            'pro_only' => false,
        ],
        'core_updated' => [
            'key' => 'core_updated',
            'name' => 'WordPress Core Updated',
            'description' => 'Running the latest WordPress version ensures you have security patches.',
            'points' => 10,
            'category' => self::CATEGORY_HIGH,
            'gate_for_tier' => null,
            'pro_only' => false,
        ],

        // Medium (5 points each)
        'plugins_updated' => [
            'key' => 'plugins_updated',
            'name' => 'All Plugins Updated',
            'description' => 'Outdated plugins can contain security vulnerabilities.',
            'points' => 5,
            'category' => self::CATEGORY_MEDIUM,
            'gate_for_tier' => null,
            'pro_only' => false,
        ],
        'audit_logs' => [
            'key' => 'audit_logs',
            'name' => 'Audit Logs',
            'description' => 'Audit logs help track security events and detect suspicious activity.',
            'points' => 5,
            'category' => self::CATEGORY_MEDIUM,
            'gate_for_tier' => 5,
            'pro_only' => true,
        ],
        'file_integrity' => [
            'key' => 'file_integrity',
            'name' => 'File Integrity Monitoring',
            'description' => 'File integrity monitoring detects unauthorized changes to your files.',
            'points' => 5,
            'category' => self::CATEGORY_MEDIUM,
            'gate_for_tier' => 5,
            'pro_only' => true,
        ],

        // Low (2 points each)
        'hide_login_url' => [
            'key' => 'hide_login_url',
            'name' => 'Hide Login URL',
            'description' => 'Hiding the login URL makes it harder for attackers to find your login page.',
            'points' => 2,
            'category' => self::CATEGORY_LOW,
            'gate_for_tier' => null,
            'pro_only' => false,
        ],
        'disable_file_editing' => [
            'key' => 'disable_file_editing',
            'name' => 'Disable File Editing',
            'description' => 'Disabling file editing prevents attackers from modifying files via the admin.',
            'points' => 2,
            'category' => self::CATEGORY_LOW,
            'gate_for_tier' => null,
            'pro_only' => false,
        ],
        'api_privacy' => [
            'key' => 'api_privacy',
            'name' => 'API Privacy',
            'description' => 'API privacy settings hide sensitive information from API responses.',
            'points' => 2,
            'category' => self::CATEGORY_LOW,
            'gate_for_tier' => null,
            'pro_only' => false,
        ],
        'content_protection' => [
            'key' => 'content_protection',
            'name' => 'Content Protection',
            'description' => 'Content protection prevents copying and unauthorized use of your content.',
            'points' => 2,
            'category' => self::CATEGORY_LOW,
            'gate_for_tier' => null,
            'pro_only' => false,
        ],
        'login_consent' => [
            'key' => 'login_consent',
            'name' => 'Custom Login Consent',
            'description' => 'Login consent banner informs users about data processing.',
            'points' => 2,
            'category' => self::CATEGORY_LOW,
            'gate_for_tier' => null,
            'pro_only' => false,
        ],
    ];

    /**
     * Tier definitions
     *
     * Each tier has:
     * - level: Numeric tier level (1-5)
     * - name: Human-readable name
     * - min_points: Minimum points to reach this tier
     * - max_points: Maximum points for this tier
     * - color: Hex color for UI display
     * - gates: Array of check keys required to reach this tier
     */
    private const TIERS = [
        1 => [
            'level' => 1,
            'name' => 'Vulnerable',
            'min_points' => 0,
            'max_points' => 19,
            'color' => '#ff471a',
            'gates' => [],
        ],
        2 => [
            'level' => 2,
            'name' => 'Basic',
            'min_points' => 20,
            'max_points' => 39,
            'color' => '#f3a81f',
            'gates' => ['ssl_enabled'],
        ],
        3 => [
            'level' => 3,
            'name' => 'Protected',
            'min_points' => 40,
            'max_points' => 59,
            'color' => '#d4e725',
            'gates' => ['ssl_enabled', '2fa_enabled', 'login_rate_limit'],
        ],
        4 => [
            'level' => 4,
            'name' => 'Hardened',
            'min_points' => 60,
            'max_points' => 79,
            'color' => '#7ada2c',
            'gates' => ['ssl_enabled', '2fa_enabled', 'login_rate_limit', 'captcha_enabled', 'password_policy'],
        ],
        5 => [
            'level' => 5,
            'name' => 'Fortress',
            'min_points' => 80,
            'max_points' => 100,
            'color' => '#873eff',
            'gates' => ['ssl_enabled', '2fa_enabled', 'login_rate_limit', 'captcha_enabled', 'password_policy', 'audit_logs', 'file_integrity'],
        ],
    ];

    /**
     * Get unique module identifier.
     *
     * @return string
     */
    public static function getId(): string
    {
        return 'security_score';
    }

    /**
     * Get human-readable module name.
     *
     * @return string
     */
    public static function getName(): string
    {
        return __('Security Score', 'ultimate-security');
    }

    /**
     * Get module domain.
     *
     * @return string
     */
    public static function getDomain(): string
    {
        return 'monitoring';
    }

    /**
     * Check if module is enabled.
     *
     * @return bool
     */
    public static function isEnabled(): bool
    {
        return true; // Always enabled
    }

    /**
     * Boot the module - register REST API routes.
     *
     * @return void
     */
    public static function boot(): void
    {
        add_action('rest_api_init', [self::class, 'register_rest_routes']);
        add_action('ultimate_security_options_updated', [self::class, 'clear_cache']);
    }

    /**
     * Register REST API routes.
     *
     * @return void
     */
    public static function register_rest_routes(): void
    {
        register_rest_route('ultimate-security/v1', '/security-score', [
            'methods' => 'GET',
            'callback' => [self::class, 'get_score_endpoint'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);

        register_rest_route('ultimate-security/v1', '/security-score/checks', [
            'methods' => 'GET',
            'callback' => [self::class, 'get_checks_endpoint'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);

        register_rest_route('ultimate-security/v1', '/security-score/refresh', [
            'methods' => 'POST',
            'callback' => [self::class, 'refresh_score_endpoint'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);
    }

    /**
     * Calculate the complete security score.
     *
     * @return array{
     *     tier: array{level: int, name: string, color: string},
     *     points: array{earned: int, max: int},
     *     nextTier: array{level: int, name: string, pointsNeeded: int, blockedBy: array}|null,
     *     categories: array<string, array{earned: int, max: int, items: array}>,
     *     gates: array<string, array{passed: bool, requiredForTier: int|null}>
     * }
     */
    public static function calculate_score(): array
    {
        // Check cache first
        $cached = get_transient(self::CACHE_KEY);
        if ($cached !== false) {
            return $cached;
        }

        $options = Utils::ultimate_security_get_option();
        $check_results = [];
        $categories = [
            self::CATEGORY_CRITICAL => ['earned' => 0, 'max' => 0, 'items' => []],
            self::CATEGORY_HIGH => ['earned' => 0, 'max' => 0, 'items' => []],
            self::CATEGORY_MEDIUM => ['earned' => 0, 'max' => 0, 'items' => []],
            self::CATEGORY_LOW => ['earned' => 0, 'max' => 0, 'items' => []],
        ];
        $gates = [];
        $total_earned = 0;
        $total_max = 0;

        // Run all security checks
        foreach (self::SECURITY_CHECKS as $key => $check) {
            $passed = self::run_check($key, $options);
            $points_earned = $passed ? $check['points'] : 0;

            // Update totals
            $total_earned += $points_earned;
            $total_max += $check['points'];

            // Update category totals
            $category = $check['category'];
            $categories[$category]['earned'] += $points_earned;
            $categories[$category]['max'] += $check['points'];
            $categories[$category]['items'][] = [
                'key' => $key,
                'name' => $check['name'],
                'description' => $check['description'],
                'points' => $check['points'],
                'earned' => $points_earned,
                'passed' => $passed,
                'pro_only' => $check['pro_only'],
            ];

            // Track gate status
            if ($check['gate_for_tier'] !== null) {
                $gates[$key] = [
                    'passed' => $passed,
                    'requiredForTier' => $check['gate_for_tier'],
                ];
            }

            $check_results[$key] = $passed;
        }

        // Calculate tier based on points and gate requirements
        $tier_info = self::calculate_tier($total_earned, $gates);

        // Calculate next tier info
        $next_tier = self::calculate_next_tier($tier_info['level'], $total_earned, $gates);

        $result = [
            'tier' => [
                'level' => $tier_info['level'],
                'name' => $tier_info['name'],
                'color' => $tier_info['color'],
            ],
            'points' => [
                'earned' => $total_earned,
                'max' => $total_max,
            ],
            'nextTier' => $next_tier,
            'categories' => $categories,
            'gates' => $gates,
        ];

        // Cache the result
        set_transient(self::CACHE_KEY, $result, self::CACHE_DURATION);

        return $result;
    }

    /**
     * Calculate the current tier based on points and gate requirements.
     *
     * @param int $points Total points earned.
     * @param array $gates Gate status array.
     * @return array{level: int, name: string, color: string, blockedBy: array}
     */
    private static function calculate_tier(int $points, array $gates): array
    {
        $current_tier = self::TIERS[1]; // Default to Vulnerable
        $blocked_by = [];

        // Find the highest tier the user qualifies for based on points
        foreach (self::TIERS as $tier) {
            if ($points >= $tier['min_points']) {
                // Check if all gates are met for this tier
                $tier_gates_met = true;
                $tier_blocked_by = [];

                foreach ($tier['gates'] as $gate_key) {
                    if (!isset($gates[$gate_key]) || !$gates[$gate_key]['passed']) {
                        $tier_gates_met = false;
                        $tier_blocked_by[] = $gate_key;
                    }
                }

                if ($tier_gates_met) {
                    $current_tier = $tier;
                    $blocked_by = [];
                } else {
                    // Store the blocking gates but don't advance tier
                    $blocked_by = $tier_blocked_by;
                }
            }
        }

        return [
            'level' => $current_tier['level'],
            'name' => $current_tier['name'],
            'color' => $current_tier['color'],
            'blockedBy' => $blocked_by,
        ];
    }

    /**
     * Calculate next tier requirements.
     *
     * @param int $current_level Current tier level.
     * @param int $current_points Current points.
     * @param array $gates Gate status array.
     * @return array{level: int, name: string, pointsNeeded: int, blockedBy: array}|null
     */
    private static function calculate_next_tier(int $current_level, int $current_points, array $gates): ?array
    {
        // If already at max tier, return null
        if ($current_level >= 5) {
            return null;
        }

        $next_level = $current_level + 1;
        $next_tier = self::TIERS[$next_level];

        // Calculate points needed
        $points_needed = max(0, $next_tier['min_points'] - $current_points);

        // Find blocking gates for next tier
        $blocked_by = [];
        foreach ($next_tier['gates'] as $gate_key) {
            if (!isset($gates[$gate_key]) || !$gates[$gate_key]['passed']) {
                $blocked_by[] = $gate_key;
            }
        }

        return [
            'level' => $next_tier['level'],
            'name' => $next_tier['name'],
            'pointsNeeded' => $points_needed,
            'blockedBy' => $blocked_by,
        ];
    }

    /**
     * Run a specific security check.
     *
     * @param string $check_key Check key.
     * @param array $options Plugin options.
     * @return bool True if check passes.
     */
    private static function run_check(string $check_key, array $options): bool
    {
        switch ($check_key) {
            case '2fa_enabled':
                return self::check_2fa_enabled($options);

            case 'ssl_enabled':
                return self::check_ssl_enabled();

            case 'login_rate_limit':
                return self::check_login_rate_limit($options);

            case 'captcha_enabled':
                return self::check_captcha_enabled($options);

            case 'password_policy':
                return self::check_password_policy($options);

            case 'core_updated':
                return self::check_core_updated();

            case 'plugins_updated':
                return self::check_plugins_updated();

            case 'audit_logs':
                return self::check_audit_logs($options);

            case 'file_integrity':
                return self::check_file_integrity($options);

            case 'hide_login_url':
                return self::check_hide_login_url($options);

            case 'disable_file_editing':
                return self::check_disable_file_editing();

            case 'api_privacy':
                return self::check_api_privacy($options);

            case 'content_protection':
                return self::check_content_protection($options);

            case 'login_consent':
                return self::check_login_consent($options);

            default:
                return false;
        }
    }

    /**
     * Check if 2FA is enabled for any method.
     *
     * Checks email 2FA, application (TOTP/HOTP) 2FA, SMS 2FA, or Passkeys.
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_2fa_enabled(array $options): bool
    {
        $two_factor = $options['security']['2fa_authentication'] ?? [];

        // Check email 2FA
        $email_enabled = self::is_enabled_value(
            $two_factor['email_authentication']['2fa_email_verification_enable'] ?? null
        );

        // Check application 2FA (TOTP/HOTP)
        $app_enabled = self::is_enabled_value(
            $two_factor['application_authentication']['2fa_application_authentication_enable'] ?? null
        );

        // Check SMS 2FA (Pro feature with credentials)
        $sms_enabled = false;
        if (self::is_pro_active()) {
            $sms_settings = $two_factor['sms_authentication'] ?? [];
            $sms_enabled = self::is_enabled_value($sms_settings['enable'] ?? null)
                && !empty($sms_settings['twilio_account_sid'])
                && !empty($sms_settings['twilio_auth_token'])
                && !empty($sms_settings['twilio_from_number']);
        }

        // Check Passkeys (Pro feature)
        $passkeys_enabled = false;
        if (self::is_pro_active()) {
            $passkey_settings = $options['security']['passkeys']['general_settings'] ?? [];
            $passkeys_enabled = self::is_enabled_value($passkey_settings['enable_passkeys'] ?? null);
        }

        return $email_enabled || $app_enabled || $sms_enabled || $passkeys_enabled;
    }

    /**
     * Check if SSL/HTTPS is enabled.
     *
     * Skips check on localhost/development environments.
     *
     * @return bool
     */
    private static function check_ssl_enabled(): bool
    {
        // Skip SSL check on localhost/dev environments
        if (self::is_development_environment()) {
            return true;
        }

        // Check if current request is HTTPS
        if (is_ssl()) {
            return true;
        }

        // Check for proxy/load balancer HTTPS
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        $forwarded_proto = isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
            ? sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_PROTO']))
            : '';
        if ($forwarded_proto === 'https') {
            return true;
        }

        // Check site URL setting
        $site_url = get_option('siteurl', '');
        return strpos($site_url, 'https://') === 0;
    }

    /**
     * Check if login rate limiting is enabled.
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_login_rate_limit(array $options): bool
    {
        return self::is_enabled_value($options['security']['login_limit']['enable'] ?? null);
    }

    /**
     * Check if CAPTCHA protection is configured.
     *
     * Checks both Google reCAPTCHA and Cloudflare Turnstile.
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_captcha_enabled(array $options): bool
    {
        // Check Google reCAPTCHA
        $recaptcha_settings = $options['security']['re_captcha'] ?? [];
        $recaptcha_enabled = self::is_enabled_value($recaptcha_settings['enable'] ?? null)
            && !empty($recaptcha_settings['site_key'])
            && !empty($recaptcha_settings['secret_key']);

        // Check Cloudflare Turnstile
        $turnstile_settings = $options['security']['cloudflare_turnstile'] ?? [];
        $turnstile_enabled = !empty($turnstile_settings['site_key'])
            && !empty($turnstile_settings['secret_key'])
            && self::has_turnstile_forms_enabled($turnstile_settings);

        return $recaptcha_enabled || $turnstile_enabled;
    }

    /**
     * Check if password policy is enabled.
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_password_policy(array $options): bool
    {
        $password_policies = $options['security']['password_policies'] ?? [];
        $min_length = isset($password_policies['min_length']) ? (int) $password_policies['min_length'] : 0;

        return self::is_enabled_value($password_policies['activate_password_policies'] ?? null)
            && $min_length > 0;
    }

    /**
     * Check if WordPress core is updated.
     *
     * Uses cached update data to avoid external API calls.
     *
     * @return bool
     */
    private static function check_core_updated(): bool
    {
        require_once ABSPATH . 'wp-admin/includes/update.php';

        $update_core = get_site_transient('update_core');

        if (!$update_core || !isset($update_core->updates)) {
            return true; // No update info available, assume up to date
        }

        foreach ($update_core->updates as $update) {
            if ($update->response === 'upgrade') {
                return false;
            }
        }

        return true;
    }

    /**
     * Check if all plugins are updated.
     *
     * Uses cached update data to avoid external API calls.
     *
     * @return bool
     */
    private static function check_plugins_updated(): bool
    {
        $update_plugins = get_site_transient('update_plugins');

        if (!$update_plugins || !isset($update_plugins->response)) {
            return true; // No update info available, assume up to date
        }

        return empty($update_plugins->response);
    }

    /**
     * Check if audit logs are enabled (Pro feature).
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_audit_logs(array $options): bool
    {
        // Check if Pro plugin is active
        if (!self::is_pro_active()) {
            return false;
        }

        return self::is_enabled_value($options['audit_logs']['enable'] ?? null);
    }

    /**
     * Check if file integrity monitoring is enabled (Pro feature).
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_file_integrity(array $options): bool
    {
        // Check if Pro plugin is active
        if (!self::is_pro_active()) {
            return false;
        }

        // Check for file integrity settings
        // The Pro plugin stores file integrity settings
        $self_defense = $options['self_defense'] ?? [];

        return self::is_enabled_value($self_defense['enabled'] ?? null)
            && self::is_enabled_value($self_defense['file_integrity_check'] ?? null);
    }

    /**
     * Check if custom/hidden login URL is enabled.
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_hide_login_url(array $options): bool
    {
        $login_security = $options['security']['login_security'] ?? [];

        return self::is_enabled_value($login_security['custom_login_url_enable'] ?? null)
            && !empty($login_security['custom_login_url']);
    }

    /**
     * Check if file editing is disabled.
     *
     * @return bool
     */
    private static function check_disable_file_editing(): bool
    {
        // Check WordPress constant
        if (defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT) {
            return true;
        }

        // Also check for DISALLOW_FILE_MODS which is more restrictive
        if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
            return true;
        }

        return false;
    }

    /**
     * Check if API privacy settings are enabled.
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_api_privacy(array $options): bool
    {
        return self::is_enabled_value($options['security']['api_privacy']['enable'] ?? null);
    }

    /**
     * Check if content protection is enabled.
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_content_protection(array $options): bool
    {
        return self::is_enabled_value($options['security']['content_protection']['enable'] ?? null);
    }

    /**
     * Check if login consent banner is enabled.
     *
     * @param array $options Plugin options.
     * @return bool
     */
    private static function check_login_consent(array $options): bool
    {
        return self::is_enabled_value(
            $options['security']['login_security']['current_banner_content_enable'] ?? null
        );
    }

    /**
     * Normalize enabled values from options.
     *
     * @param mixed $value
     * @return bool
     */
    private static function is_enabled_value(mixed $value): bool
    {
        return $value === '1' || $value === 1 || $value === true;
    }

    /**
     * Check if Turnstile is enabled for any form.
     *
     * @param array $settings Turnstile settings.
     * @return bool
     */
    private static function has_turnstile_forms_enabled(array $settings): bool
    {
        $flags = [
            'wordpress_login',
            'wordpress_register',
            'wordpress_reset_password',
            'wordpress_comment',
        ];

        foreach ($flags as $flag) {
            if (self::is_enabled_value($settings[$flag] ?? null)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if running in a development environment.
     *
     * @return bool
     */
    private static function is_development_environment(): bool
    {
        $site_url = get_option('siteurl', '');

        // Check for localhost
        if (strpos($site_url, 'localhost') !== false) {
            return true;
        }

        // Check for .local domain
        if (strpos($site_url, '.local') !== false) {
            return true;
        }

        // Check for .test domain
        if (strpos($site_url, '.test') !== false) {
            return true;
        }

        // Check for .dev domain
        if (strpos($site_url, '.dev') !== false) {
            return true;
        }

        // Check for 127.0.0.1
        if (strpos($site_url, '127.0.0.1') !== false) {
            return true;
        }

        // Check for port-based dev URLs
        if (preg_match('/localhost:\d+/', $site_url)) {
            return true;
        }

        // Check WP_ENVIRONMENT_TYPE
        if (function_exists('wp_get_environment_type')) {
            $env = wp_get_environment_type();
            if (in_array($env, ['local', 'development'], true)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if the Pro plugin is active.
     *
     * @return bool
     */
    private static function is_pro_active(): bool
    {
        return defined('ULTIMATE_SECURITY_PRO_VERSION')
            || class_exists('WPUltimateSecurity\UltimateSecurityPro\Bootstrap\Plugin');
    }

    /**
     * Clear the score cache.
     *
     * Should be called when security settings are changed.
     * Not needed for normal operations as cache auto-expires after 5 minutes.
     *
     * @return void
     */
    public static function clear_cache(): void
    {
        delete_transient(self::CACHE_KEY);
    }

    /**
     * REST endpoint: Get security score.
     *
     * @param \WP_REST_Request $request Request object.
     * @return \WP_REST_Response
     */
    public static function get_score_endpoint(\WP_REST_Request $request): \WP_REST_Response
    {
        $score_data = self::calculate_score();

        return new \WP_REST_Response([
            'success' => true,
            'data' => $score_data,
        ], 200);
    }

    /**
     * REST endpoint: Get all security checks with detailed info.
     *
     * @param \WP_REST_Request $request Request object.
     * @return \WP_REST_Response
     */
    public static function get_checks_endpoint(\WP_REST_Request $request): \WP_REST_Response
    {
        $score_data = self::calculate_score();

        // Add tier definitions for frontend
        $tiers = [];
        foreach (self::TIERS as $tier) {
            $tiers[$tier['level']] = [
                'level' => $tier['level'],
                'name' => $tier['name'],
                'minPoints' => $tier['min_points'],
                'maxPoints' => $tier['max_points'],
                'color' => $tier['color'],
                'gates' => $tier['gates'],
            ];
        }

        return new \WP_REST_Response([
            'success' => true,
            'data' => array_merge($score_data, [
                'tiers' => $tiers,
                'checks' => self::SECURITY_CHECKS,
            ]),
        ], 200);
    }

    /**
     * REST endpoint: Refresh security score (clear cache and recalculate).
     *
     * @param \WP_REST_Request $request Request object.
     * @return \WP_REST_Response
     */
    public static function refresh_score_endpoint(\WP_REST_Request $request): \WP_REST_Response
    {
        self::clear_cache();
        $score_data = self::calculate_score();

        return new \WP_REST_Response([
            'success' => true,
            'data' => $score_data,
        ], 200);
    }
}
