<?php
/**
 * VMPFence Reputation Scanner
 * 
 * Implements reputation checking for domains and IPs using:
 * - Google Safe Browsing API
 * - DNS-based blocklists (SURBL, Spamhaus DBL)
 * - RBL checks for IP reputation
 *
 * @package VMPFence
 * @since 1.0.0
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

class VMPFence_Reputation_Scanner {
    
    private $debug_log = [];
    
    /**
     * Check domain blocklist status
     */
    public function check_domain_blocklist() {
        $issues_found = 0;
        $this->debug_log[] = "Starting domain blocklist check";
        
        $site_url = site_url();
        $domain = wp_parse_url($site_url, PHP_URL_HOST);
        
        if (!$domain) {
            $this->debug_log[] = "Could not extract domain from site URL: {$site_url}";
            return ['issues_found' => 0, 'debug_log' => $this->debug_log];
        }
        
        $this->debug_log[] = "Checking domain: {$domain}";
        
        // Check if this is a private/local IP (skip reputation checks for local development)
        $is_private_ip = filter_var($domain, FILTER_VALIDATE_IP) && !filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE);
        
        if ($is_private_ip) {
            $this->debug_log[] = "Private IP detected ({$domain}) - skipping domain blocklist checks for local development";
            $this->save_scan_summary('blocklist_check', $issues_found, [
                'domain_checked' => $domain,
                'gsb_checked' => class_exists('VMPFence_URL_Safety_Checker'),
                'dns_lists_checked' => ['SURBL'],
                'skipped_reason' => 'Private IP address'
            ]);
            return ['issues_found' => 0, 'debug_log' => $this->debug_log];
        }
        
        // Check Google Safe Browsing using existing VMPFence class
        if (class_exists('VMPFence_URL_Safety_Checker')) {
            $this->debug_log[] = "Using VMPFence URL Safety Checker for Google Safe Browsing";
            $gsb_checker = new VMPFence_URL_Safety_Checker();
            $gsb_result = $gsb_checker->check_url_reputation($site_url);
            
            if (isset($gsb_result['safe']) && !$gsb_result['safe']) {
                $threats = 'Google Safe Browsing flagged this domain';
                if (isset($gsb_result['details']['threats']) && is_array($gsb_result['details']['threats'])) {
                    $threat_types = array_column($gsb_result['details']['threats'], 'threat_type');
                    $threats = 'Google Safe Browsing: ' . implode(', ', $threat_types);
                }
                
                $this->create_issue([
                    'type' => 'domain_blocklist',
                    'severity' => 'critical',
                    'description' => "Domain found in Google Safe Browsing: {$threats}",
                    'file_path' => $domain
                ]);
                $issues_found++;
                $this->debug_log[] = "Google Safe Browsing: Domain flagged - {$threats}";
            } else {
                $this->debug_log[] = "Google Safe Browsing: Domain is clean";
            }
        } else {
            $this->debug_log[] = "VMPFence_URL_Safety_Checker class not found, skipping Google Safe Browsing check";
        }
        
        // Check DNS-based blocklists
        $dns_results = $this->check_dns_blocklists($domain);
        $issues_found += $dns_results;

        // Save scan summary to database
        $this->save_scan_summary('blocklist_check', $issues_found, [
            'domain_checked' => $domain,
            'gsb_checked' => class_exists('VMPFence_URL_Safety_Checker'),
            'dns_lists_checked' => ['SURBL']
        ]);

        return [
            'issues_found' => $issues_found,
            'debug_log' => $this->debug_log
        ];
    }
    
    /**
     * Check for spamvertising activity
     */
    public function check_spamvertising() {
        $issues_found = 0;
        $this->debug_log[] = "Starting spamvertising check";
        
        $domain = wp_parse_url(site_url(), PHP_URL_HOST);
        
        if (!$domain) {
            $this->debug_log[] = "Could not extract domain for spamvertising check";
            return ['issues_found' => 0, 'debug_log' => $this->debug_log];
        }
        
        $this->debug_log[] = "Checking spamvertising for domain: {$domain}";
        
        // Check if this is a private/local IP (skip reputation checks for local development)
        $is_private_ip = filter_var($domain, FILTER_VALIDATE_IP) && !filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE);
        
        if ($is_private_ip) {
            $this->debug_log[] = "Private IP detected ({$domain}) - skipping spamvertising checks for local development";
            $this->save_scan_summary('spamvertising_checks', $issues_found, [
                'domain_checked' => $domain,
                'lists_checked' => ['Spamhaus DBL', 'SURBL'],
                'skipped_reason' => 'Private IP address'
            ]);
            return ['issues_found' => 0, 'debug_log' => $this->debug_log];
        }
        
        // Check Spamhaus DBL
        if ($this->dns_lookup("{$domain}.dbl.spamhaus.org")) {
            $this->create_issue([
                'type' => 'spamvertising',
                'severity' => 'critical',
                'description' => "Domain found in Spamhaus Domain Block List (DBL)",
                'file_path' => $domain
            ]);
            $issues_found++;
            $this->debug_log[] = "Spamhaus DBL: Domain flagged";
        } else {
            $this->debug_log[] = "Spamhaus DBL: Domain is clean";
        }
        
        // Check SURBL
        if ($this->dns_lookup("{$domain}.multi.surbl.org")) {
            $this->create_issue([
                'type' => 'spamvertising',
                'severity' => 'critical',
                'description' => "Domain found in SURBL spam database",
                'file_path' => $domain
            ]);
            $issues_found++;
            $this->debug_log[] = "SURBL: Domain flagged";
        } else {
            $this->debug_log[] = "SURBL: Domain is clean";
        }

        // Save scan summary to database
        $this->save_scan_summary('spamvertising_checks', $issues_found, [
            'domain_checked' => $domain,
            'lists_checked' => ['Spamhaus DBL', 'SURBL']
        ]);

        return [
            'issues_found' => $issues_found,
            'debug_log' => $this->debug_log
        ];
    }
    
    /**
     * Check IP spam reputation
     */
    public function check_ip_spam() {
        $issues_found = 0;
        $this->debug_log[] = "Starting IP spam reputation check";
        
        $server_ip = $this->get_server_ip();
        if (!$server_ip) {
            $this->debug_log[] = "Could not determine server IP";
            return ['issues_found' => 0, 'debug_log' => $this->debug_log];
        }
        
        $this->debug_log[] = "Checking IP: {$server_ip}";
        
        // Check if this is a private IP (local development)
        $is_private_ip = !filter_var($server_ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE);
        
        if ($is_private_ip) {
            $this->debug_log[] = "Private IP detected ({$server_ip}) - skipping RBL checks but saving scan result";
        } else {
            $this->debug_log[] = "Public IP detected ({$server_ip}) - performing RBL checks";
        }
        
        // Check multiple RBLs
        $rbls = [
            'sbl.spamhaus.org' => 'Spamhaus SBL',
            'css.spamhaus.org' => 'Spamhaus CSS',
            'b.barracudacentral.org' => 'Barracuda RBL',
            'dnsbl.sorbs.net' => 'SORBS',
            'bl.spamcop.net' => 'SpamCop'
        ];
        
        $reverse_ip = implode('.', array_reverse(explode('.', $server_ip)));
        
        // Only perform RBL checks for public IPs
        if (!$is_private_ip) {
            foreach ($rbls as $rbl => $name) {
                $lookup = "{$reverse_ip}.{$rbl}";
                if ($this->dns_lookup($lookup)) {
                    $this->create_issue([
                        'type' => 'ip_spam',
                        'severity' => 'high',
                        'description' => "Server IP {$server_ip} found in {$name}",
                        'file_path' => $server_ip
                    ]);
                    $issues_found++;
                    $this->debug_log[] = "{$name}: IP flagged";
                } else {
                    $this->debug_log[] = "{$name}: IP is clean";
                }
            }
        } else {
            $this->debug_log[] = "RBL checks skipped for private IP - no issues detected";
        }

        // Save scan summary to database
        $this->debug_log[] = "Attempting to save IP spam check summary with {$issues_found} issues";
        try {
            $this->save_scan_summary('spam_check', $issues_found, [
                'ip_checked' => $server_ip,
                'rbls_checked' => array_keys($rbls)
            ]);
        } catch (Exception $e) {
            $this->debug_log[] = "ERROR saving scan summary: " . $e->getMessage();
        }
        $this->debug_log[] = "IP spam check summary save completed";

        return [
            'issues_found' => $issues_found,
            'debug_log' => $this->debug_log
        ];
    }
    
    /**
     * Check DNS-based blocklists for domain
     */
    private function check_dns_blocklists($domain) {
        $issues_found = 0;
        
        // SURBL Multi check for domain reputation
        if ($this->dns_lookup("{$domain}.multi.surbl.org")) {
            $this->create_issue([
                'type' => 'domain_blocklist',
                'severity' => 'critical',
                'description' => "Domain found in SURBL blocklist",
                'file_path' => $domain
            ]);
            $issues_found++;
            $this->debug_log[] = "SURBL blocklist: Domain flagged";
        } else {
            $this->debug_log[] = "SURBL blocklist: Domain is clean";
        }
        
        return $issues_found;
    }
    
    /**
     * Create an issue in the database
     */
    private function create_issue($issue_data) {
        global $wpdb;

        $issues_table = $wpdb->prefix . 'vmpfence_scan_issues';

        $result = $wpdb->insert($issues_table, [
            'scan_id' => 0, // Will be updated by scan engine if needed
            'file_path' => $issue_data['file_path'],
            'issue_type' => 'reputation',
            'type' => $issue_data['type'],
            'severity' => $issue_data['severity'],
            'description' => $issue_data['description'],
            'file_hash' => '',
            'file_size' => 0,
            'detected_time' => current_time('mysql'),
            'status' => 'new'
        ]);

        if ($result === false) {
            $this->debug_log[] = "Database error: " . $wpdb->last_error;
        } else {
            $this->debug_log[] = "Created issue: " . $issue_data['description'];
        }
    }

    /**
     * Save scan summary to vmpfence_scan_results table
     */
    private function save_scan_summary($scan_type, $issues_found, $scan_data = []) {
        global $wpdb;

        $this->debug_log[] = "save_scan_summary called with scan_type: {$scan_type}, issues_found: {$issues_found}";

        $scan_results_table = $wpdb->prefix . 'vmpfence_scan_results';

        $insert_data = [
            'scan_type' => $scan_type,
            'scan_time' => current_time('mysql'),
            'issues_found' => $issues_found,
            'scan_status' => 'completed',
            'scan_data' => wp_json_encode($scan_data)
        ];

        $result = $wpdb->insert($scan_results_table, $insert_data);

        if ($result === false) {
            $this->debug_log[] = "ERROR: Failed to save scan summary for {$scan_type}: " . $wpdb->last_error;
        } else {
            $this->debug_log[] = "Successfully saved scan summary for {$scan_type} with {$issues_found} issues (insert ID: {$wpdb->insert_id})";
        }
    }

    /**
     * Perform DNS lookup
     */
    private function dns_lookup($hostname) {
        // Use WordPress transient cache to avoid repeated lookups
        $cache_key = 'vmpfence_dns_' . md5($hostname);
        $cached_result = get_transient($cache_key);
        
        if ($cached_result !== false) {
            return $cached_result === 'found';
        }
        
        $result = dns_get_record($hostname, DNS_A);
        $found = !empty($result);
        
        // Cache result for 1 hour
        set_transient($cache_key, $found ? 'found' : 'clean', HOUR_IN_SECONDS);
        
        return $found;
    }
    
    /**
     * Get server IP address
     */
    private function get_server_ip() {
        // Try multiple methods to detect server IP
        $methods = [
            isset($_SERVER['SERVER_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_ADDR'])) : null,
            gethostbyname(isset($_SERVER['SERVER_NAME']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_NAME'])) : ''),
            gethostbyname(wp_parse_url(site_url(), PHP_URL_HOST))
        ];
        
        foreach ($methods as $ip) {
            // First try to find a public IP
            if ($ip && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                return $ip;
            }
        }

        
        // If no public IP found, allow private IPs for local development
        foreach ($methods as $ip) {
            if ($ip && filter_var($ip, FILTER_VALIDATE_IP)) {
                $this->debug_log[] = "Using private IP for local development: {$ip}";
                return $ip;
            }
        }

        
        return null;
    }
    
    /**
     * Calculate reputation check percentage based on enabled options
     * 33.3% for each of the 3 reputation checks
     *
     * @return float Percentage (0-100)
     */
    public static function calculate_reputation_percentage() {
        $score = 0.0;
        
        // Get scan options - following VMPFence's naming convention
        $scan_options = array(
            'scansEnabled_checkGSB' => VMPFence_Config::get('scansEnabled_checkGSB', false),
            'spamvertizeCheck' => VMPFence_Config::get('spamvertizeCheck', false),
            'checkSpamIP' => VMPFence_Config::get('checkSpamIP', false)
        );
        
        // Each enabled check contributes 33.3%
        if ($scan_options['scansEnabled_checkGSB']) { 
            $score += 0.333; // Domain blocklist check
        }
        if ($scan_options['spamvertizeCheck']) { 
            $score += 0.333; // Spamvertising check  
        }
        if ($scan_options['checkSpamIP']) { 
            $score += 0.333; // IP spam check
        }
        
        return round($score * 100); // Convert to percentage (0-100)
    }
    
    /**
     * Get reputation check status list
     * Shows which individual checks are enabled/disabled
     *
     * @return array Status information for each check
     */
    public static function get_reputation_status_list() {
        $scan_options = array(
            'scansEnabled_checkGSB' => VMPFence_Config::get('scansEnabled_checkGSB', false),
            'spamvertizeCheck' => VMPFence_Config::get('spamvertizeCheck', false),
            'checkSpamIP' => VMPFence_Config::get('checkSpamIP', false)
        );
        
        $status_list = array();
        
        $reputation_checks = array(
            'scansEnabled_checkGSB' => 'Check if this website is on a domain blocklist',
            'spamvertizeCheck' => 'Check if this website is being "Spamvertised"',
            'checkSpamIP' => 'Check if this website IP is generating spam'
        );
        
        foreach ($reputation_checks as $option => $description) {
            $status_list[] = array(
                'option' => $option,
                'enabled' => $scan_options[$option],
                'percentage' => 33.3, // Each check worth 33.3%
                'description' => $description
            );
        }
        
        return $status_list;
    }
}