<?php

/**
 * VMPFence URL Safety Checker
 * 
 * URL reputation checking using Google Safe Browsing API
 * 
 * @package VMPFence
 * @subpackage Security
 * @since 1.0.0
 */

if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
}

class VMPFence_URL_Safety_Checker {
    
    private $api_key;
    private $cache_duration = 3600; // 1 hour default
    private $cache_file;
    private $api_endpoint = 'https://safebrowsing.googleapis.com/v4/threatMatches:find';
    private $rate_limit = 10000; // Per day
    private $request_count = 0;
    private $debug_log = [];
    
    // Google Safe Browsing threat types
    private $threat_types = [
        'MALWARE',
        'SOCIAL_ENGINEERING',
        'UNWANTED_SOFTWARE',
        'POTENTIALLY_HARMFUL_APPLICATION'
    ];
    
    // Platform types to check
    private $platform_types = [
        'WINDOWS',
        'LINUX',
        'ANDROID',
        'OSX',
        'IOS',
        'ANY_PLATFORM'
    ];
    
    public function __construct($api_key = null) {
        $this->api_key = ($api_key !== null) ? $api_key : $this->get_api_key();
        $this->cache_file = plugin_dir_path(__FILE__) . 'vmpfence-url-cache.json';
        $this->init_url_checker();
    }
    
    /**
     * Initialize URL safety checker
     * Required by roadmap for URL reputation checking
     */
    private function init_url_checker() {
        // Load cached results if available
        if (file_exists($this->cache_file)) {
            $this->load_cache();
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] URL Safety Checker initialized';
        $this->debug_log[] = '[' . current_time('H:i:s') . '] API Key: ' . ($this->api_key ? 'Present' : 'Missing');
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Cache file: ' . $this->cache_file;
    }
    
    /**
     * Check URL reputation against Google Safe Browsing
     */
    public function check_url_reputation($url) {
        if (empty($url) || !$this->is_valid_url($url)) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Invalid URL provided: ' . $url;
            return [
                'safe' => false,
                'error' => 'Invalid URL format',
                'threat_type' => null,
                'details' => []
            ];
        }
        
        // Check cache first
        $cached_result = $this->get_cached_result($url);
        if ($cached_result !== false) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Cache hit for URL: ' . $url;
            return $cached_result;
        }
        
        // Check rate limits
        if (!$this->check_rate_limits()) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Rate limit exceeded';
            return [
                'safe' => null,
                'error' => 'Rate limit exceeded',
                'threat_type' => null,
                'details' => []
            ];
        }
        
        // Perform API check
        $result = $this->perform_safe_browsing_check($url);
        
        // Cache the result
        $this->cache_url_result($url, $result);
        
        return $result;
    }
    
    /**
     * Batch check multiple URLs
     * Required by roadmap: batch_check_urls() method
     */
    public function batch_check_urls($urls) {
        if (!is_array($urls)) {
            return [];
        }
        
        $results = [];
        $uncached_urls = [];
        
        // First pass: check cache for all URLs
        foreach ($urls as $url) {
            $cached_result = $this->get_cached_result($url);
            if ($cached_result !== false) {
                $results[$url] = $cached_result;
            } else {
                $uncached_urls[] = $url;
            }
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Batch check: ' . count($urls) . ' total, ' . count($uncached_urls) . ' uncached';
        
        // Batch check uncached URLs
        if (!empty($uncached_urls) && $this->check_rate_limits()) {
            $batch_results = $this->perform_batch_safe_browsing_check($uncached_urls);
            
            foreach ($batch_results as $url => $result) {
                $results[$url] = $result;
                $this->cache_url_result($url, $result);
            }
        }
        
        return $results;
    }
    
    /**
     * Cache URL results for performance
     * Required by roadmap: cache_url_results() method
     */
    public function cache_url_results($results, $ttl = null) {
        $ttl = $ttl ?: $this->cache_duration;
        
        foreach ($results as $url => $result) {
            $this->cache_url_result($url, $result, $ttl);
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Cached ' . count($results) . ' URL results with TTL: ' . $ttl;
    }
    
    /**
     * Perform Google Safe Browsing API check
     * Core API integration method
     */
    private function perform_safe_browsing_check($url) {
        if (!$this->api_key || empty(trim($this->api_key))) {
            return [
                'safe' => null,
                'error' => 'No API key configured',
                'threat_type' => null,
                'details' => []
            ];
        }
        
        $request_body = [
            'client' => [
                'clientId' => 'vmpfence-scanner',
                'clientVersion' => '1.10.0'
            ],
            'threatInfo' => [
                'threatTypes' => $this->threat_types,
                'platformTypes' => $this->platform_types,
                'threatEntryTypes' => ['URL'],
                'threatEntries' => [
                    ['url' => $url]
                ]
            ]
        ];
        
        $response = $this->make_api_request($request_body);
        $this->request_count++;
        
        return $this->process_api_response($response, $url);
    }
    
    /**
     * Perform batch Google Safe Browsing API check
     * Optimized for multiple URLs
     */
    private function perform_batch_safe_browsing_check($urls) {
        if (!$this->api_key || empty(trim($this->api_key))) {
            $error_result = [
                'safe' => null,
                'error' => 'No API key configured',
                'threat_type' => null,
                'details' => []
            ];
            
            return array_fill_keys($urls, $error_result);
        }
        
        // Build threat entries for all URLs
        $threat_entries = [];
        foreach ($urls as $url) {
            $threat_entries[] = ['url' => $url];
        }
        
        $request_body = [
            'client' => [
                'clientId' => 'vmpfence-scanner',
                'clientVersion' => '1.10.0'
            ],
            'threatInfo' => [
                'threatTypes' => $this->threat_types,
                'platformTypes' => $this->platform_types,
                'threatEntryTypes' => ['URL'],
                'threatEntries' => $threat_entries
            ]
        ];
        
        $response = $this->make_api_request($request_body);
        $this->request_count++;
        
        return $this->process_batch_api_response($response, $urls);
    }
    
    /**
     * Make HTTP request to Google Safe Browsing API
     * Handles authentication and error handling
     */
    private function make_api_request($request_body) {
        $url = $this->api_endpoint . '?key=' . $this->api_key;
        
        $args = [
            'method' => 'POST',
            'headers' => [
                'Content-Type' => 'application/json',
            ],
            'body' => json_encode($request_body),
            'timeout' => 10
        ];
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Making API request to Google Safe Browsing';
        
        $response = wp_remote_request($url, $args);
        
        if (is_wp_error($response)) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] API request failed: ' . $response->get_error_message();
            return false;
        }
        
        $response_code = wp_remote_retrieve_response_code($response);
        $response_body = wp_remote_retrieve_body($response);
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] API response code: ' . $response_code;
        
        if ($response_code !== 200) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] API error response: ' . $response_body;
            return false;
        }
        
        return json_decode($response_body, true);
    }
    
    /**
     * Process single URL API response
     * Converts API response to standardized format
     */
    private function process_api_response($response, $url) {
        if ($response === false) {
            return [
                'safe' => null,
                'error' => 'API request failed',
                'threat_type' => null,
                'details' => []
            ];
        }
        
        // No matches means URL is safe
        if (empty($response['matches'])) {
            return [
                'safe' => true,
                'error' => null,
                'threat_type' => null,
                'details' => [
                    'checked_at' => current_time('mysql'),
                    'api_response' => 'No threats detected'
                ]
            ];
        }
        
        // Process threat matches
        $threats = [];
        foreach ($response['matches'] as $match) {
            $threats[] = [
                'threat_type' => $match['threatType'] ?? 'UNKNOWN',
                'platform_type' => $match['platformType'] ?? 'UNKNOWN',
                'threat_entry_type' => $match['threatEntryType'] ?? 'URL'
            ];
        }
        
        return [
            'safe' => false,
            'error' => null,
            'threat_type' => $threats[0]['threat_type'] ?? 'UNKNOWN',
            'details' => [
                'checked_at' => current_time('mysql'),
                'threats' => $threats,
                'api_response' => 'Threats detected'
            ]
        ];
    }
    
    /**
     * Process batch URL API response
     * Handles multiple URL results
     */
    private function process_batch_api_response($response, $urls) {
        $results = [];
        
        // Initialize all URLs as safe
        foreach ($urls as $url) {
            $results[$url] = [
                'safe' => true,
                'error' => null,
                'threat_type' => null,
                'details' => [
                    'checked_at' => current_time('mysql'),
                    'api_response' => 'No threats detected'
                ]
            ];
        }
        
        if ($response === false) {
            $error_result = [
                'safe' => null,
                'error' => 'API request failed',
                'threat_type' => null,
                'details' => []
            ];
            
            return array_fill_keys($urls, $error_result);
        }
        
        // Process threat matches if any
        if (!empty($response['matches'])) {
            foreach ($response['matches'] as $match) {
                $threat_url = $match['threat']['url'] ?? '';
                
                if (in_array($threat_url, $urls)) {
                    $results[$threat_url] = [
                        'safe' => false,
                        'error' => null,
                        'threat_type' => $match['threatType'] ?? 'UNKNOWN',
                        'details' => [
                            'checked_at' => current_time('mysql'),
                            'threat_type' => $match['threatType'] ?? 'UNKNOWN',
                            'platform_type' => $match['platformType'] ?? 'UNKNOWN',
                            'api_response' => 'Threat detected'
                        ]
                    ];
                }
            }
        }
        
        return $results;
    }
    
    /**
     * Get cached URL result
     * Performance optimization for repeated checks
     */
    private function get_cached_result($url) {
        if (!file_exists($this->cache_file)) {
            return false;
        }
        
        $cache = json_decode(file_get_contents($this->cache_file), true);
        if (!$cache) {
            return false;
        }
        
        $url_hash = md5($url);
        
        if (!isset($cache[$url_hash])) {
            return false;
        }
        
        $cached_data = $cache[$url_hash];
        
        // Check if cache has expired
        if (isset($cached_data['expires']) && $cached_data['expires'] < time()) {
            return false;
        }
        
        return $cached_data['result'];
    }
    
    /**
     * Cache URL result to file
     * Implements TTL-based caching
     */
    private function cache_url_result($url, $result, $ttl = null) {
        $ttl = $ttl ?: $this->cache_duration;
        $url_hash = md5($url);
        
        $cache = [];
        if (file_exists($this->cache_file)) {
            $cache = json_decode(file_get_contents($this->cache_file), true) ?: [];
        }
        
        $cache[$url_hash] = [
            'url' => $url,
            'result' => $result,
            'cached_at' => time(),
            'expires' => time() + $ttl
        ];
        
        // Clean expired entries while we're here
        $cache = $this->clean_expired_cache($cache);
        
        file_put_contents($this->cache_file, json_encode($cache, JSON_PRETTY_PRINT), LOCK_EX);
    }
    
    /**
     * Load cache from file
     * Initialize cache system
     */
    private function load_cache() {
        if (!file_exists($this->cache_file)) {
            return;
        }
        
        $cache = json_decode(file_get_contents($this->cache_file), true);
        if ($cache) {
            $cache = $this->clean_expired_cache($cache);
            file_put_contents($this->cache_file, json_encode($cache, JSON_PRETTY_PRINT), LOCK_EX);
        }
    }
    
    /**
     * Clean expired cache entries
     * Maintenance function for cache optimization
     */
    private function clean_expired_cache($cache) {
        $current_time = time();
        
        foreach ($cache as $key => $entry) {
            if (isset($entry['expires']) && $entry['expires'] < $current_time) {
                unset($cache[$key]);
            }
        }
        
        return $cache;
    }
    
    /**
     * Check API rate limits
     * Prevents exceeding Google Safe Browsing quotas
     */
    private function check_rate_limits() {
        return $this->request_count < $this->rate_limit;
    }
    
    /**
     * Validate URL format
     * Basic URL validation before API calls
     */
    private function is_valid_url($url) {
        return filter_var($url, FILTER_VALIDATE_URL) !== false;
    }
    
    /**
     * Get API key from configuration
     * Retrieves API key from VMPFence config only
     */
    private function get_api_key() {
        if (class_exists('VMPFence_Config')) {
            return VMPFence_Config::get('google_safebrowsing_api_key', '');
        }
        
        return '';
    }
    
    /**
     * Extract URLs from file content
     * Utility method for malware scanner integration
     */
    public function extract_urls_from_content($content) {
        $urls = [];
        
        // Pattern for HTTP/HTTPS URLs
        $url_pattern = '/https?:\/\/(?:[a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}(?:\/[^\s]*)?/';
        
        preg_match_all($url_pattern, $content, $matches);
        
        if (!empty($matches[0])) {
            $urls = array_unique($matches[0]);
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Extracted ' . count($urls) . ' URLs from content';
        
        return $urls;
    }
    
    /**
     * Get cache statistics
     * Performance monitoring for cache system
     */
    public function get_cache_stats() {
        if (!file_exists($this->cache_file)) {
            return [
                'total_entries' => 0,
                'expired_entries' => 0,
                'valid_entries' => 0,
                'cache_size_bytes' => 0
            ];
        }
        
        $cache = json_decode(file_get_contents($this->cache_file), true) ?: [];
        $current_time = time();
        $expired_count = 0;
        $valid_count = 0;
        
        foreach ($cache as $entry) {
            if (isset($entry['expires']) && $entry['expires'] < $current_time) {
                $expired_count++;
            } else {
                $valid_count++;
            }
        }
        
        return [
            'total_entries' => count($cache),
            'expired_entries' => $expired_count,
            'valid_entries' => $valid_count,
            'cache_size_bytes' => filesize($this->cache_file)
        ];
    }
    
    /**
     * Get debug log for troubleshooting
     * Debugging and monitoring support
     */
    public function get_debug_log() {
        return $this->debug_log;
    }
    
    /**
     * Clear URL cache
     * Maintenance function
     */
    public function clear_cache() {
        if (file_exists($this->cache_file)) {
            unlink($this->cache_file);
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] URL cache cleared';
    }
    
    /**
     * Get API usage statistics
     * Monitor API quota usage
     */
    public function get_api_stats() {
        return [
            'requests_made' => $this->request_count,
            'rate_limit' => $this->rate_limit,
            'remaining_requests' => max(0, $this->rate_limit - $this->request_count),
            'api_key_configured' => !empty($this->api_key)
        ];
    }
}
