<?php
declare(strict_types=1);


namespace ProRank\SEO\Core;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}


/**
 * Security Validator
 * 
 * Multi-layer security validation system
 */


class SecurityValidator {
    
    /**
     * Validation checkpoints
     */
    private const CHECKPOINTS = [
        'cp_init' => 'initialization',
        'cp_admin' => 'admin_access',
        'cp_api' => 'api_request',
        'cp_feature' => 'feature_usage',
        'cp_cron' => 'cron_execution',
        'cp_ajax' => 'ajax_request',
        'cp_rest' => 'rest_endpoint',
        'cp_module' => 'module_load',
        'cp_asset' => 'asset_generation',
        'cp_export' => 'data_export',
        'cp_import' => 'data_import',
        'cp_analyze' => 'seo_analysis',
        'cp_ai' => 'ai_feature',
        'cp_perf' => 'performance_opt',
        'cp_audit' => 'site_audit',
    ];
    
    /**
     * Validation cache
     */
    private static ?array $validationCache = null;
    private static ?int $cacheExpiry = null;
    
    /**
     * Failed validation tracking
     */
    private static array $failures = [];
    private static int $failureThreshold = 3;
    
    /**
     * Perform security validation at checkpoint
     */
    public static function validate(string $checkpoint, array $context = []): bool {
        // Check if checkpoint exists
        if (!isset(self::CHECKPOINTS[$checkpoint])) {
            return true; // Unknown checkpoints pass by default
        }
        
        // Use cached result if valid
        if (self::isCacheValid()) {
            return self::$validationCache['status'] ?? false;
        }
        
        // Perform multi-layer validation
        $validators = [
            'validateLicense',
            'validateDomain',
            'validateFingerprint',
            'validateIntegrity',
            'validateExpiry',
        ];
        
        $results = [];
        foreach ($validators as $validator) {
            if (method_exists(self::class, $validator)) {
                $results[$validator] = self::$validator($context);
            }
        }
        
        // Calculate overall status
        $failureCount = count(array_filter($results, fn($r) => !$r));
        $status = $failureCount <= 1; // Allow one validator to fail
        
        // Track failures
        if (!$status) {
            self::trackFailure($checkpoint, $results);
        }
        
        // Cache result
        self::$validationCache = [
            'status' => $status,
            'timestamp' => time(),
            'results' => $results,
        ];
        self::$cacheExpiry = time() + 300; // 5 minute cache
        
        // Apply delayed failure if threshold reached
        if (self::shouldDelayFailure()) {
            return true; // Pass now, fail later
        }
        
        return $status;
    }
    
    /**
     * Validate license status
     */
    private static function validateLicense(array $context): bool {
        // Skip during very early initialization stages
        if (!did_action('plugins_loaded')) {
            return true;
        }
        
        // Check if Plugin class exists
        if (!class_exists('\\ProRank\\SEO\\Plugin')) {
            return false;
        }
        
        // Try to get plugin instance safely
        try {
            $plugin = \ProRank\SEO\Plugin::get_instance();
            if (!$plugin) {
                return false;
            }
            
            // Check if license service is available
            if (!method_exists($plugin, 'license_manager')) {
                return true; // Services not initialized yet
            }
            
            $licenseManager = $plugin->license_manager();
            if (!$licenseManager) {
                return false;
            }
            
            // Quick JWT check
            $licenseData = $licenseManager->get_license_data();
            $token = $licenseData['license_token'] ?? '';
            
            if (empty($token)) {
                return false;
            }
            
            // Verify token without external call
            return $licenseManager->verify_token($token);
        } catch (\Exception $e) {
            // Handle any exceptions during validation
            prorank_log('[ProRank SecurityValidator] License validation error: ' . $e->getMessage());
            return true; // Allow operation to continue
        }
    }
    
    /**
     * Validate domain matches license
     */
    private static function validateDomain(array $context): bool {
        // Skip during very early initialization stages
        if (!did_action('plugins_loaded')) {
            return true;
        }
        
        try {
            $plugin = \ProRank\SEO\Plugin::get_instance();
            if (!$plugin || !method_exists($plugin, 'license_manager')) {
                return true; // Services not initialized yet
            }
            
            $licenseManager = $plugin->license_manager();
            if (!$licenseManager) {
                return true;
            }
            
            $licenseData = $licenseManager->get_license_data();
            $licensedDomain = $licenseData['domain'] ?? '';
            $currentDomain = wp_parse_url(home_url(), PHP_URL_HOST);
            
            // Allow localhost for development
            if (in_array($currentDomain, ['localhost', '127.0.0.1'])) {
                return true;
            }
            
            // Exact match or subdomain match
            return $licensedDomain === $currentDomain || 
                   str_ends_with($currentDomain, '.' . $licensedDomain);
        } catch (\Exception $e) {
            prorank_log('[ProRank SecurityValidator] Domain validation error: ' . $e->getMessage());
            return true; // Allow operation to continue
        }
    }
    
    /**
     * Validate system fingerprint
     */
    private static function validateFingerprint(array $context): bool {
        $stored = get_option('prorank_system_fingerprint');
        $current = self::generateFingerprint();
        
        // First run - store fingerprint
        if (empty($stored)) {
            update_option('prorank_system_fingerprint', $current);
            return true;
        }
        
        // Compare fingerprints
        return hash_equals($stored, $current);
    }
    
    /**
     * Validate file integrity
     */
    private static function validateIntegrity(array $context): bool {
        // Skip in development mode
        if (defined('PRORANK_DEV_MODE') && PRORANK_DEV_MODE) {
            return true;
        }
        
        $manifest = self::getIntegrityManifest();
        if (empty($manifest)) {
            return true; // No manifest = no check
        }
        
        // Check critical files
        $criticalFiles = [
            'prorank-seo.php',
            'includes/Plugin.php',
            'includes/Core/LicenseManager.php',
        ];
        
        $basePath = plugin_dir_path(dirname(dirname(__DIR__)));
        
        foreach ($criticalFiles as $file) {
            if (!isset($manifest[$file])) {
                continue;
            }
            
            $fullPath = $basePath . $file;
            if (!file_exists($fullPath)) {
                return false;
            }
            
            $hash = hash_file('sha256', $fullPath);
            if ($hash !== $manifest[$file]) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * Validate license expiry
     */
    private static function validateExpiry(array $context): bool {
        // Skip during very early initialization stages
        if (!did_action('plugins_loaded')) {
            return true;
        }
        
        try {
            $plugin = \ProRank\SEO\Plugin::get_instance();
            if (!$plugin || !method_exists($plugin, 'license_manager')) {
                return true; // Services not initialized yet
            }
            
            $licenseManager = $plugin->license_manager();
            if (!$licenseManager) {
                return true;
            }
            
            $licenseData = $licenseManager->get_license_data();
            $expiresAt = $licenseData['expires_at'] ?? 0;
            if ($expiresAt === 0) {
                return true; // No expiry set
            }
            
            return $expiresAt > time();
        } catch (\Exception $e) {
            prorank_log('[ProRank SecurityValidator] Expiry validation error: ' . $e->getMessage());
            return true; // Allow operation to continue
        }
    }
    
    /**
     * Generate system fingerprint
     */
    private static function generateFingerprint(): string {
        $components = [
            'domain' => wp_parse_url(home_url(), PHP_URL_HOST),
            'prefix' => $GLOBALS['wpdb']->prefix,
            'php' => PHP_VERSION,
            'server' => $_SERVER['SERVER_SOFTWARE'] ?? 'unknown',
            'db_name' => DB_NAME,
        ];
        
        // Add more entropy
        if (function_exists('disk_total_space')) {
            $components['disk'] = disk_total_space('/');
        }
        
        return hash('sha256', json_encode($components));
    }
    
    /**
     * Get integrity manifest
     */
    private static function getIntegrityManifest(): array {
        $manifestFile = plugin_dir_path(dirname(dirname(__DIR__))) . '.integrity';
        
        if (!file_exists($manifestFile)) {
            return [];
        }
        
        $content = file_get_contents($manifestFile);
        $decrypted = self::decryptManifest($content);
        
        return json_decode($decrypted, true) ?? [];
    }
    
    /**
     * Decrypt integrity manifest
     */
    private static function decryptManifest(string $encrypted): string {
        // Use compiled-in key (this would be generated during build)
        // In production, this key would be different for each build
        $key = 'a1b2c3d4e5f6789012345678901234567'; // Example key
        
        // For development, try to load from key file
        if (defined('PRORANK_DEV_MODE') && PRORANK_DEV_MODE) {
            $keyFile = plugin_dir_path(dirname(dirname(__DIR__))) . '.integrity-key';
            if (file_exists($keyFile)) {
                $key = trim(file_get_contents($keyFile));
            }
        }
        
        $decrypted = '';
        $encrypted = base64_decode($encrypted);
        for ($i = 0; $i < strlen($encrypted); $i++) {
            $decrypted .= $encrypted[$i] ^ $key[$i % strlen($key)];
        }
        
        return $decrypted;
    }
    
    /**
     * Check if validation cache is valid
     */
    private static function isCacheValid(): bool {
        return self::$cacheExpiry !== null && 
               self::$cacheExpiry > time() &&
               self::$validationCache !== null;
    }
    
    /**
     * Track validation failure
     */
    private static function trackFailure(string $checkpoint, array $results): void {
        self::$failures[] = [
            'checkpoint' => $checkpoint,
            'timestamp' => time(),
            'results' => $results,
        ];
        
        // Keep only recent failures
        self::$failures = array_filter(
            self::$failures,
            fn($f) => $f['timestamp'] > (time() - 3600)
        );
        
        // Log suspicious activity
        if (count(self::$failures) >= self::$failureThreshold) {
            // Keep failure tracking local-only.
        }
    }
    
    /**
     * Determine if failure should be delayed
     */
    private static function shouldDelayFailure(): bool {
        // Delay failure for better obfuscation
        $delayProbability = min(count(self::$failures) * 0.2, 0.8);
        $random = wp_rand(0, 1000000) / 1000000;
        return $random < $delayProbability;
    }
    
    /**
     * Perform hidden validation (honeypot)
     */
    public static function performHiddenCheck(): void {
        // This method appears to do nothing but actually validates
        $context = ['hidden' => true];
        $result = self::validate('cp_hidden', $context);
        
        if (!$result) {
            // Subtle degradation
            add_filter('prorank_max_features', fn($max) => intval($max * 0.5));
            add_filter('prorank_api_timeout', fn($timeout) => $timeout * 3);
        }
    }
}
