<?php

namespace WPUltimateSecurity\UltimateSecurity\Support\Validation;

use WP_Error;
use WP_REST_Request;

/**
 * Pro Feature Middleware
 *
 * Validates that Pro features are only accessible when the Pro plugin is active.
 * This is a CRITICAL security measure - Pro features must be validated server-side,
 * not just hidden in the UI.
 *
 * Usage:
 * ```php
 * // In REST route registration
 * register_rest_route('ultimate-security/v1', '/pro-feature', [
 *     'methods' => 'POST',
 *     'callback' => [$this, 'proFeatureHandler'],
 *     'permission_callback' => ProFeatureMiddleware::requirePro(
 *         Capabilities::MANAGE_2FA,
 *         'sms_authentication'
 *     ),
 * ]);
 *
 * // Or wrap an existing callback
 * $handler = ProFeatureMiddleware::wrap(
 *     [$this, 'smsAuthHandler'],
 *     'sms_authentication'
 * );
 * ```
 *
 * @package WPUltimateSecurity\UltimateSecurity\Support\Validation
 * @since 2.0.0
 */
class ProFeatureMiddleware
{
    /**
     * Pro plugin main file constant.
     */
    private const PRO_PLUGIN_FILE = 'ultimate-security-pro/ultimate-security-pro.php';

    /**
     * Pro features that require validation.
     * Note: Strings are not translated here - they are translated at runtime via getFeatureName().
     *
     * @var array<string, string>
     */
    private static array $proFeatures = [
        // 2FA Features
        'sms_authentication' => 'SMS Authentication',
        'webauthn_authentication' => 'WebAuthn/Passkeys',
        'backup_codes' => 'Backup Codes',
        'trusted_devices' => 'Trusted Devices',

        // Activity Logs
        'activity_logs' => 'Activity Logs',
        'auth_logs' => 'Authentication Logs',
        'file_events' => 'File Event Logs',

        // Security Features
        'security_score' => 'Security Score',
        'advanced_firewall' => 'Advanced Firewall',

        // Maintenance
        'database_cleanup' => 'Database Cleanup',
        'scheduled_scans' => 'Scheduled Scans',

        // Notifications
        'slack_notifications' => 'Slack Notifications',
        'telegram_notifications' => 'Telegram Notifications',
    ];

    /**
     * Get the translated feature name.
     *
     * @param string $feature The feature identifier.
     *
     * @return string
     */
    private static function getFeatureName(string $feature): string
    {
        if (!isset(self::$proFeatures[$feature])) {
            return __('This feature', 'ultimate-security');
        }

        // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
        return __(self::$proFeatures[$feature], 'ultimate-security');
    }

    /**
     * Check if the Pro plugin is active.
     *
     * @return bool
     */
    public static function isProActive(): bool
    {
        if (!function_exists('is_plugin_active')) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }

        return is_plugin_active(self::PRO_PLUGIN_FILE);
    }

    /**
     * Check if a feature is a Pro feature.
     *
     * @param string $feature The feature identifier.
     *
     * @return bool
     */
    public static function isProFeature(string $feature): bool
    {
        return isset(self::$proFeatures[$feature]);
    }

    /**
     * Check if a Pro feature is available.
     *
     * @param string $feature The feature identifier.
     *
     * @return bool
     */
    public static function hasProFeature(string $feature): bool
    {
        // If not a Pro feature, it's available
        if (!self::isProFeature($feature)) {
            return true;
        }

        // Pro features require Pro plugin
        return self::isProActive();
    }

    /**
     * Create a permission callback that requires Pro plugin.
     *
     * @param string|callable $basePermission Base permission check (capability or callable).
     * @param string|null     $feature        Optional feature identifier for specific messaging.
     *
     * @return callable
     */
    public static function requirePro(string|callable $basePermission, ?string $feature = null): callable
    {
        return function (WP_REST_Request $request) use ($basePermission, $feature) {
            // First check Pro status
            if (!self::isProActive()) {
                $featureName = $feature !== null
                    ? self::getFeatureName($feature)
                    : __('This feature', 'ultimate-security');

                return new WP_Error(
                    'ultimate_security_pro_required',
                    sprintf(
                        /* translators: %s: feature name */
                        __('%s requires Ultimate Security Pro.', 'ultimate-security'),
                        $featureName
                    ),
                    ['status' => 403, 'feature' => $feature]
                );
            }

            // Then check base permission
            if (is_callable($basePermission)) {
                return $basePermission($request);
            }

            // Assume it's a capability string
            if (!current_user_can($basePermission)) {
                return new WP_Error(
                    'ultimate_security_permission_denied',
                    __('You do not have permission to access this feature.', 'ultimate-security'),
                    ['status' => 403]
                );
            }

            return true;
        };
    }

    /**
     * Wrap a callback to validate Pro status before execution.
     *
     * @param callable    $callback The original callback.
     * @param string|null $feature  The Pro feature identifier.
     *
     * @return callable
     */
    public static function wrap(callable $callback, ?string $feature = null): callable
    {
        return function (WP_REST_Request $request) use ($callback, $feature) {
            // Check Pro status
            if (!self::isProActive()) {
                $featureName = $feature !== null
                    ? self::getFeatureName($feature)
                    : __('This feature', 'ultimate-security');

                return new WP_Error(
                    'ultimate_security_pro_required',
                    sprintf(
                        /* translators: %s: feature name */
                        __('%s requires Ultimate Security Pro.', 'ultimate-security'),
                        $featureName
                    ),
                    ['status' => 403, 'feature' => $feature]
                );
            }

            // Execute original callback
            return $callback($request);
        };
    }

    /**
     * Validate a Pro feature from request data.
     *
     * Useful for validating Pro settings in options updates.
     *
     * @param array  $data    The request data.
     * @param array  $mapping Map of data keys to Pro features.
     *
     * @return WP_Error|true Returns WP_Error if Pro feature is used without Pro.
     */
    public static function validateRequest(array $data, array $mapping): WP_Error|bool
    {
        if (self::isProActive()) {
            return true;
        }

        foreach ($mapping as $key => $feature) {
            // Check if this key is set and has a truthy value
            $value = self::getNestedValue($data, $key);

            if ($value !== null && $value !== '' && $value !== '0' && $value !== false) {
                $featureName = self::getFeatureName($feature);

                return new WP_Error(
                    'ultimate_security_pro_required',
                    sprintf(
                        /* translators: %s: feature name */
                        __('%s requires Ultimate Security Pro.', 'ultimate-security'),
                        $featureName
                    ),
                    ['status' => 403, 'feature' => $feature, 'key' => $key]
                );
            }
        }

        return true;
    }

    /**
     * Get all registered Pro features.
     *
     * @return array<string, string>
     */
    public static function getProFeatures(): array
    {
        return self::$proFeatures;
    }

    /**
     * Register a new Pro feature.
     *
     * @param string $identifier  The feature identifier.
     * @param string $displayName The display name for error messages.
     *
     * @return void
     */
    public static function registerProFeature(string $identifier, string $displayName): void
    {
        self::$proFeatures[$identifier] = $displayName;
    }

    /**
     * Get a nested value using dot notation.
     *
     * @param array  $data    The data array.
     * @param string $key     The dot-notation key.
     * @param mixed  $default Default value.
     *
     * @return mixed
     */
    private static function getNestedValue(array $data, string $key, mixed $default = null): mixed
    {
        $keys = explode('.', $key);
        $value = $data;

        foreach ($keys as $segment) {
            if (!is_array($value) || !array_key_exists($segment, $value)) {
                return $default;
            }
            $value = $value[$segment];
        }

        return $value;
    }

    /**
     * Get error response for Pro feature.
     *
     * @param string $feature The feature identifier.
     *
     * @return WP_Error
     */
    public static function getProRequiredError(string $feature): WP_Error
    {
        $featureName = self::getFeatureName($feature);

        return new WP_Error(
            'ultimate_security_pro_required',
            sprintf(
                /* translators: %s: feature name */
                __('%s requires Ultimate Security Pro.', 'ultimate-security'),
                $featureName
            ),
            ['status' => 403, 'feature' => $feature]
        );
    }
}
