<?php
/**
 * @file qtrSettings.php
 * @brief Settings management class with built-in validation and serialization
 */
require_once('qtrLogger.php');

class QutteraSettings
{
    // Scan mode constants
    const SCAN_MODE_NORMAL = 'normal';
    const SCAN_MODE_HEURISTIC = 'heuristic';
    const SHARED_HOSTING = 'shared';
    const DEDICATED_SERVER = 'dedicated';

    // Private properties for each setting
    private $setup_uuid;
    private $alert_email;
    private $alarms_enabled;
    private $cure_mode;
    private $fs_integrity_mode;
    private $continuous_scan_period;
    private $protection_mode;
    private $scan_mode;
    private $blocked_ips;
    private $manually_blocked_ips;
    private $whitelist_ips;
    private $trusted_proxy_ips;
    private $trusted_proxy_enabled;
    private $bruteforce_enabled;
    private $bot_protection_enabled;
    private $hosting_type;

    // Validation rules
    private static $validation_rules = [
        'alert_email' => [
            'type' => 'email',
            'required' => true,
            'message' => 'Invalid email address'
        ],
        'alarms_enabled' => [
            'type' => 'boolean',
            'required' => false,
            'default' => false
        ],
        'scan_mode' => [
            'type' => 'select',
            'allowed' => [self::SCAN_MODE_NORMAL, self::SCAN_MODE_HEURISTIC],
            'required' => false,
            'default' => self::SCAN_MODE_NORMAL,
            'message' => 'Invalid scan mode'
        ],
        'cure_mode' => [
            'type' => 'select',
            'allowed' => ['on', 'off', 'quarantine'],
            'required' => false,
            'default' => 'off',
            'message' => 'Invalid cure mode'
        ],
        'fs_integrity_mode' => [
            'type' => 'select',
            'allowed' => ['off', 'fix'],
            'required' => false,
            'default' => 'off',
            'message' => 'Invalid file system integrity mode'
        ],
        'continuous_scan_period' => [
            'type' => 'text',
            'required' => false,
            'default' => '',
            'max_length' => 10
        ],
        'protection_mode' => [
            'type' => 'select',
            'allowed' => ['learning', 'bypass', 'operational'],
            'required' => false,
            'default' => 'operational',
            'message' => 'Invalid protection mode'
        ],
        'blocked_ips' => [
            'type' => 'textarea',
            'required' => false,
            'default' => '',
            'validator' => 'validate_ip_list'
        ],
        'manually_blocked_ips' => [
            'type' => 'textarea',
            'required' => false,
            'default' => '',
            'validator' => 'validate_ip_list'
        ],
        'whitelist_ips' => [
            'type' => 'textarea',
            'required' => false,
            'default' => '',
            'validator' => 'validate_ip_list'
        ],
        'trusted_proxy_ips' => [
            'type' => 'textarea',
            'required' => false,
            'default' => '',
            'validator' => 'validate_ip_list'
        ],
        'trusted_proxy_enabled' => [
            'type' => 'bool',
            'required' => false,
            'default' => false
        ],
        'bruteforce_enabled' => [
            'type' => 'bool',
            'required' => false,
            'default' => true
        ],
        'bot_protection_enabled' => [
            'type' => 'bool',
            'required' => false,
            'default' => true
        ],
        'hosting_type' => [
            'type' => 'select',
            'allowed' => [self::SHARED_HOSTING, self::DEDICATED_SERVER],
            'required' => false,
            'default' => self::SHARED_HOSTING,
            'message' => 'Invalid hosting type'
        ]
    ];

    /**
     * Constructor with default values
     */
    public function __construct()
    {
        $uuid = get_option( 'qtr_scanner_uuid', '' );
        if ( ! empty( $uuid ) ) {
            $this->setup_uuid = $uuid;
        } else {
            $this->setup_uuid = wp_generate_uuid4();
            update_option( 'qtr_scanner_uuid', $this->setup_uuid, false );
        }

        $this->alert_email = get_option('admin_email');
        $this->alarms_enabled = false;
        $this->scan_mode = self::SCAN_MODE_NORMAL;
        $this->cure_mode = 'quarantine';
        $this->fs_integrity_mode = 'fix';
        $this->continuous_scan_period = '';
        $this->protection_mode = 'operational';
        $this->blocked_ips = '';
        $this->manually_blocked_ips = '';
        $this->whitelist_ips = '';
        $this->trusted_proxy_ips = '';
        $this->trusted_proxy_enabled = false;
        $this->bruteforce_enabled = false;
        $this->bot_protection_enabled = false;
        $this->hosting_type = self::SHARED_HOSTING;
    }

    // ===== GETTERS =====

    public function GetSetupUUID()
    {
        return $this->setup_uuid;
    }

    public function GetAlertEmail()
    {
        return $this->alert_email;
    }

    public function GetAlarmsEnabled()
    {
        return (bool) $this->alarms_enabled;
    }

    public function GetScanMode()
    {
        return $this->scan_mode;
    }

    /**
     * Check if scan mode is heuristic
     * 
     * @return bool True if heuristic mode is enabled, false for normal mode
     */
    public function IsHeuristicMode()
    {
        return $this->scan_mode === self::SCAN_MODE_HEURISTIC;
    }

    public function GetCureMode()
    {
        return $this->cure_mode;
    }

    public function GetFsIntegrityMode()
    {
        return $this->fs_integrity_mode;
    }

    public function GetContinuousScanPeriod()
    {
        return $this->continuous_scan_period;
    }

    public function GetProtectionMode()
    {
        return $this->protection_mode;
    }

    public function GetBlockedIPs()
    {
        return $this->blocked_ips;
    }

    public function GetManuallyBlockedIPs()
    {
        return $this->manually_blocked_ips;
    }

    public function GetWhitelistIPs()
    {
        return $this->whitelist_ips;
    }

    public function GetTrustedProxyIPs()
    {
        return $this->trusted_proxy_ips;
    }

    public function GetTrustedProxyEnabled()
    {
        return (bool) $this->trusted_proxy_enabled;
    }

    public function GetBruteForceEnabled()
    {
        return (bool) $this->bruteforce_enabled;
    }

    public function GetBotProtectionEnabled()
    {
        return (bool) $this->bot_protection_enabled;
    }

    public function GetHostingType()
    {
        return $this->hosting_type;
    }

    /**
     * Get all settings as array
     * 
     * @return array All settings
     */
    public function GetAll()
    {
        $output = [
            'setup_uuid' => $this->setup_uuid,
            'alert_email' => $this->alert_email,
            'alarms_enabled' => $this->alarms_enabled,
            'scan_mode' => $this->scan_mode,
            'cure_mode' => $this->cure_mode,
            'fs_integrity_mode' => $this->fs_integrity_mode,
            'continuous_scan_period' => $this->continuous_scan_period,
            'protection_mode' => $this->protection_mode,
            'blocked_ips' => $this->blocked_ips,
            'manually_blocked_ips' => $this->manually_blocked_ips,
            'whitelist_ips' => $this->whitelist_ips,
            'trusted_proxy_ips' => $this->trusted_proxy_ips,
            'trusted_proxy_enabled' => $this->trusted_proxy_enabled,
            'bruteforce_enabled' => $this->bruteforce_enabled,
            'bot_protection_enabled' => $this->bot_protection_enabled,
            'hosting_type' => $this->hosting_type
        ];

        //$logger = new CQtrLogger();
        //$logger->Info("GetAll: " . print_r($output, true));

        return $output;
    }

    // ===== SETTERS WITH VALIDATION =====

    /**
     * Set UUID
     * 
     * @param string $value UUID value
     * @return bool True on success, false on failure
     */
    public function SetSetupUUID($value)
    {
        $this->setup_uuid = (string) $value;
        return true;
    }

    /**
     * Set alert email with validation
     * 
     * @param string $value Email address
     * @return bool True on success, false if invalid email
     */
    public function SetAlertEmail($value)
    {
        $email = sanitize_email($value);
        
        if (!is_email($email)) {
            $logger = new CQtrLogger();
            $logger->Error( "Invalid email address: {$value}" );
            return false;
        }
        
        $this->alert_email = $email;
        return true;
    }

    /**
     * Set alarms enabled flag
     * 
     * @param mixed $value Boolean or truthy value
     * @return bool Always true
     */
    public function SetAlarmsEnabled($value)
    {
        $this->alarms_enabled = (bool) $this->CastToBoolean($value);
        return true;
    }

    /**
     * Set scan mode with validation
     * 
     * @param string $value Scan mode value ('normal' or 'heuristic')
     * @return bool True on success, false if invalid
     */
    public function SetScanMode($value)
    {
        $allowed = [self::SCAN_MODE_NORMAL, self::SCAN_MODE_HEURISTIC];
        $value = sanitize_text_field($value);
        
        if (!in_array($value, $allowed, true)) {
            $logger = new CQtrLogger();
            $logger->Error( "Invalid scan mode: {$value}. Allowed: " . implode(', ', $allowed) );
            return false;
        }
        
        $this->scan_mode = $value;
        return true;
    }

        
    /**
     * Set cure mode with validation
     * 
     * @param string $value Cure mode value
     * @return bool True on success, false if invalid
     */
    public function SetCureMode($value)
    {
        $allowed = ['on', 'off', 'quarantine'];
        $value = sanitize_text_field($value);
        
        if (!in_array($value, $allowed, true)) {
            $logger = new CQtrLogger();
            $logger->Error( "Invalid cure mode: {$value}. Allowed: " . implode(', ', $allowed) );
            return false;
        }
        
        $this->cure_mode = $value;
        return true;
    }

    /**
     * Set file system integrity mode with validation
     * 
     * @param string $value FS integrity mode value
     * @return bool True on success, false if invalid
     */
    public function SetFsIntegrityMode($value)
    {
        $allowed = ['off', 'fix'];
        $value = sanitize_text_field($value);
        
        if (!in_array($value, $allowed, true)) {
            $logger = new CQtrLogger();
            $logger->Error( "Invalid file system integrity mode: {$value}. Allowed: " . implode(', ', $allowed) );
            return false;
        }
        
        $this->fs_integrity_mode = $value;
        return true;
    }

    /**
     * Set continuous scan period
     * 
     * @param string $value Scan period value
     * @return bool True on success, false if too long
     */
    public function SetContinuousScanPeriod($value)
    {
        $value = sanitize_text_field($value);
        
        if (strlen($value) > 10) {
            $logger = new CQtrLogger();
            $logger->Error( "Continuous scan period exceeds maximum length" );
            return false;
        }
        
        $this->continuous_scan_period = $value;
        return true;
    }

    /**
     * Set protection mode with validation
     * 
     * @param string $value Protection mode value
     * @return bool True on success, false if invalid
     */
    public function SetProtectionMode($value)
    {
        $allowed = ['learning', 'bypass', 'operational'];
        $value = sanitize_text_field($value);
        
        if (!in_array($value, $allowed, true)) {
            $logger = new CQtrLogger();
            $logger->Error( "Invalid protection mode: {$value}. Allowed: " . implode(', ', $allowed) );
            return false;
        }
        
        $this->protection_mode = $value;
        return true;
    }

    /**
     * Set blocked IPs with validation
     * 
     * @param string $value IP list (one per line)
     * @return bool True on success, false if invalid IPs
     */
    public function SetBlockedIPs($value)
    {
        $normalized = sanitize_textarea_field($value);
        
        // Validate and clean IPs
        $validation = $this->ValidateIPList($normalized);
        if (!$validation['valid']) {
            $logger = new CQtrLogger();
            $logger->Error( "IP validation error: " . $validation['error'] );
            return false;
        }
        
        $this->blocked_ips = $validation['data'];
        return true;
    }

    /**
     * Set manually blocked IPs with validation
     * 
     * @param string $value IP list (semicolon-separated)
     * @return bool True on success, false if invalid IPs
     */
    public function SetManuallyBlockedIPs($value)
    {
        $normalized = sanitize_textarea_field($value);
        
        // Validate and clean IPs
        $validation = $this->ValidateIPList($normalized);
        if (!$validation['valid']) {
            $logger = new CQtrLogger();
            $logger->Error( "Manually blocked IP validation error: " . $validation['error'] );
            return false;
        }
        
        // Store as semicolon-separated for consistency with settings storage
        $this->manually_blocked_ips = str_replace("\n", ';', $validation['data']);
        return true;
    }

    /**
     * Set whitelist IPs with validation
     * 
     * @param string $value IP list (semicolon-separated)
     * @return bool True on success, false if invalid IPs
     */
    public function SetWhitelistIPs($value)
    {
        $normalized = sanitize_textarea_field($value);
                
        // Validate and clean IPs
        $validation = $this->ValidateIPList($normalized);
        if (!$validation['valid']) {
            $logger = new CQtrLogger();
            $logger->Error( "Whitelist IP validation error: " . $validation['error'] );
            return false;
        }
        
        // Store as semicolon-separated for consistency with settings storage
        $this->whitelist_ips = str_replace("\n", ';', $validation['data']);
        return true;
    }

    /**
     * Set trusted proxy IPs with validation
     * 
     * @param string $value Proxy IP list (semicolon-separated)
     * @return bool True on success, false if invalid IPs
     */
    public function SetTrustedProxyIPs($value)
    {
        $normalized = sanitize_textarea_field($value);
                
        // Validate and clean IPs
        $validation = $this->ValidateIPList($normalized);
        if (!$validation['valid']) {
            $logger = new CQtrLogger();
            $logger->Error( "Trusted proxy IP validation error: " . $validation['error'] );
            return false;
        }
        
        // Store as semicolon-separated for consistency with settings storage
        $this->trusted_proxy_ips = str_replace("\n", ';', $validation['data']);
        return true;
    }

    /**
     * Set trusted proxy enabled status
     * 
     * @param mixed $value Boolean or truthy value
     * @return bool Always true
     */
    public function SetTrustedProxyEnabled($value)
    {
        $this->trusted_proxy_enabled = (bool) $this->CastToBoolean($value);
        return true;
    }

    /**
     * Set brute-force enabled status
     * 
     * @param bool|string $value Enable (true/1/'on') or disable (false/0/'off')
     * @return bool True on success
     */
    public function SetBruteForceEnabled($value)
    {
        // Handle various boolean representations
        if (is_string($value)) {
            $value = strtolower(trim($value));
            $this->bruteforce_enabled = in_array($value, ['1', 'on', 'true', 'yes']);
        } else {
            $this->bruteforce_enabled = (bool) $value;
        }
        return true;
    }

    /**
     * Set bot protection enabled status
     * 
     * @param bool|string $value Enable (true/1/'on') or disable (false/0/'off')
     * @return bool True on success
     */
    public function SetBotProtectionEnabled($value)
    {
        // Handle various boolean representations
        if (is_string($value)) {
            $value = strtolower(trim($value));
            $this->bot_protection_enabled = in_array($value, ['1', 'on', 'true', 'yes']);
        } else {
            $this->bot_protection_enabled = (bool) $value;
        }
        return true;
    }

    /**
     * Set hosting type with validation
     *
     * @param string $value 'shared' or 'dedicated'
     * @return bool True on success, false if invalid
     */
    public function SetHostingType($value)
    {
        $allowed = [self::SHARED_HOSTING, self::DEDICATED_SERVER];
        $value = sanitize_text_field($value);

        if (!in_array($value, $allowed, true)) {
            $logger = new CQtrLogger();
            $logger->Error("Invalid hosting type: {$value}. Allowed: " . implode(', ', $allowed));
            return false;
        }

        $this->hosting_type = $value;
        return true;
    }

    /**
     * Resolve conflicts between blacklist, whitelist, and trusted proxy IPs.
     * 
     * Rules:
     *  - If an IP is whitelisted, remove it from blacklist
     *  - If an IP is in trusted proxy list, remove it from blacklist
     * 
     * This prevents having the same IP in both allow and block lists.
     * 
     * @return void
     */
    private function resolve_ip_conflicts()
    {
        $logger = new CQtrLogger();
        
        // Get current IP lists
        $blacklist = $this->parse_ip_list($this->manually_blocked_ips);
        $whitelist = $this->parse_ip_list($this->whitelist_ips);
        $trusted_proxies = $this->parse_ip_list($this->trusted_proxy_ips);
        
        if (empty($blacklist)) {
            return; // Nothing to resolve
        }
        
        $removed_from_blacklist = [];
        
        // Remove any blacklisted IPs that are also whitelisted
        foreach ($whitelist as $whitelisted_ip) {
            if (in_array($whitelisted_ip, $blacklist, true)) {
                $removed_from_blacklist[] = $whitelisted_ip;
                $blacklist = array_diff($blacklist, [$whitelisted_ip]);
                $logger->Warning("Removed IP from blacklist because it is whitelisted: {$whitelisted_ip}");
            }
        }
        
        // Remove any blacklisted IPs that are also trusted proxies
        foreach ($trusted_proxies as $proxy_ip) {
            if (in_array($proxy_ip, $blacklist, true)) {
                $removed_from_blacklist[] = $proxy_ip;
                $blacklist = array_diff($blacklist, [$proxy_ip]);
                $logger->Warning("Removed IP from blacklist because it is a trusted proxy: {$proxy_ip}");
            }
        }
        
        // Update manually_blocked_ips with cleaned blacklist
        if (!empty($removed_from_blacklist)) {
            $this->manually_blocked_ips = implode(';', $blacklist);
            $logger->Info("IP conflict resolution complete. Removed " . count($removed_from_blacklist) . " IP(s) from blacklist: " . implode(', ', $removed_from_blacklist));
        }
    }

    /**
     * Parse IP list string into array.
     * Handles both semicolon and newline separators.
     * 
     * @param string $ip_list IP list string
     * @return array Array of IPs
     */
    private function parse_ip_list($ip_list)
    {
        if (empty($ip_list)) {
            return [];
        }
        
        // Replace newlines with semicolons and split
        $normalized = str_replace(["\n", "\r"], ';', $ip_list);
        $ips = array_map('trim', explode(';', $normalized));
        
        // Remove empty entries
        return array_filter($ips, function($ip) {
            return !empty($ip);
        });
    }

    /**
     * Set multiple values from array with validation
     * 
     * @param array $data Array of setting key-value pairs
     * @return bool True on success, false if any validation fails
     */
    public function SetFromArray($data)
    {
        $logger = new CQtrLogger();
        if (!is_array($data)) {
            $logger->Error( "SetFromArray: data must be an array" );
            return false;
        }

        foreach ($data as $key => $value) {
            $result = false;
            
            switch ($key) {
                case 'setup_uuid':
                    $result = $this->SetSetupUUID($value);
                    break;
                case 'alert_email':
                    $result = $this->SetAlertEmail($value);
                    break;
                case 'alarms_enabled':
                    $result = $this->SetAlarmsEnabled($value);
                    break;
                case 'scan_mode':
                    $result = $this->SetScanMode($value);
                    break;
                case 'cure_mode':
                    $result = $this->SetCureMode($value);
                    break;
                case 'fs_integrity_mode':
                    $result = $this->SetFsIntegrityMode($value);
                    break;
                case 'continuous_scan_period':
                    $result = $this->SetContinuousScanPeriod($value);
                    break;
                case 'protection_mode':
                    $result = $this->SetProtectionMode($value);
                    break;
                case 'blocked_ips':
                    $result = $this->SetBlockedIPs($value);
                    break;
                case 'manually_blocked_ips':
                    $result = $this->SetManuallyBlockedIPs($value);
                    break;
                case 'whitelist_ips':
                    $result = $this->SetWhitelistIPs($value);
                    break;
                case 'trusted_proxy_ips':
                    $result = $this->SetTrustedProxyIPs($value);
                    break;
                case 'trusted_proxy_enabled':
                    $result = $this->SetTrustedProxyEnabled($value);
                    break;
                case 'bruteforce_enabled':
                    $result = $this->SetBruteForceEnabled($value);
                    break;
                case 'bot_protection_enabled':
                    $result = $this->SetBotProtectionEnabled($value);
                    break;
                case 'hosting_type':
                    $result = $this->SetHostingType($value);
                    break;
                default:
                    $logger->Error( "Field {$key} not supported" );
                    $result= true;
            }
            
            // Return false if any setter fails
            if (!$result) {
                $logger->Error( "Validation failed for field: {$key}" );
                return false;
            }
        }

        return true;
    }

    // ===== VALIDATION HELPERS & STATIC METHODS =====

    /**
     * Cast value to boolean, handling string 'true'/'false' and 1/'1'
     * 
     * @param mixed $value Value to cast
     * @return bool Boolean value
     */
    private function CastToBoolean($value)
    {
        if (is_bool($value)) {
            return $value;
        }
        if (!is_string($value)){
            return (bool) $value;    
        }
        
        $lowercase = strtolower($value);

        if (in_array($lowercase, ['true', 'on', 'yes', '1'])) {
            return true;
        }

        return false;
    }

    /**
     * Validate single IP address or CIDR notation (instance method)
     * 
     * @param string $ip IP address or CIDR (e.g., "192.168.1.1" or "10.0.0.0/8")
     * @return bool True if valid IP or CIDR
     */
    private function IsValidIPOrCIDR($ip)
    {
        // Check if it contains CIDR notation
        if (strpos($ip, '/') !== false) {
            list($addr, $prefix) = explode('/', $ip);
            
            // Validate prefix is numeric and in valid range
            if (!is_numeric($prefix) || $prefix < 0 || $prefix > 128) {
                return false;
            }
            
            // IPv4 CIDR: prefix 0-32
            // IPv6 CIDR: prefix 0-128
            if (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
                return $prefix <= 32;
            } elseif (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
                return $prefix <= 128;
            }
            return false;
        }
        
        // Regular IP address (IPv4 or IPv6)
        return filter_var($ip, FILTER_VALIDATE_IP) !== false;
    }

    /**
     * Validate single IP address or CIDR notation (static method)
     * 
     * @param string $ip IP address or CIDR (e.g., "192.168.1.1" or "10.0.0.0/8")
     * @return bool True if valid IP or CIDR
     */
    public static function IsValidIPOrCIDRStatic($ip)
    {
        // Check if it contains CIDR notation
        if (strpos($ip, '/') !== false) {
            list($addr, $prefix) = explode('/', $ip);
            
            // Validate prefix is numeric and in valid range
            if (!is_numeric($prefix) || $prefix < 0 || $prefix > 128) {
                return false;
            }
            
            // IPv4 CIDR: prefix 0-32
            // IPv6 CIDR: prefix 0-128
            if (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
                return $prefix <= 32;
            } elseif (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
                return $prefix <= 128;
            }
            return false;
        }
        
        // Regular IP address (IPv4 or IPv6)
        return filter_var($ip, FILTER_VALIDATE_IP) !== false;
    }

    /**
     * Validate and parse IP list (semicolon-separated)
     * 
     * @param string $ipList IP addresses, semicolon-separated (e.g. "192.168.1.1;10.0.0.1;192.168.1.5" or "10.0.0.0/8;192.168.1.0/24")
     * @return array Array with 'valid' (bool), 'data' (string), and 'error' (string) keys
     */
    private function ValidateIPList($ipList)
    {
        if (empty($ipList)) {
            return ['valid' => true, 'data' => '', 'error' => ''];
        }

        // Split by semicolon and trim each IP
        $ips = array_filter(array_map('trim', explode(';', $ipList)));
        $validIPs = [];
        $errors = [];

        foreach ($ips as $ip) {
            if (empty($ip)) {
                continue;
            }
            
            if (!$this->IsValidIPOrCIDR($ip)) {
                $errors[] = "Invalid IP address: {$ip}";
            } else {
                // Avoid duplicates
                if (!in_array($ip, $validIPs, true)) {
                    $validIPs[] = $ip;
                }
            }
        }

        if (!empty($errors)) {
            return [
                'valid' => false,
                'data' => '',
                'error' => 'IP validation failed: ' . implode('; ', $errors)
            ];
        }

        return [
            'valid' => true,
            'data' => implode(';', $validIPs),
            'error' => ''
        ];
    }

    /**
     * Validate input data array (static method for pre-initialization validation)
     * 
     * @param array $inputData POST data or similar input array
     * @return bool True if all fields are valid, false otherwise
     */
    public static function ValidateInput($inputData)
    {
        if (!is_array($inputData)) {
            $logger = new CQtrLogger();
            $logger->Error( "ValidateInput: Input must be an array" );
            return false;
        }

        foreach (self::$validation_rules as $field => $rules) {
            $value = isset($inputData[$field]) ? $inputData[$field] : null;

            // Check required fields
            if ($rules['required'] && empty($value)) {
                $logger = new CQtrLogger();
                $logger->Error( "Field '{$field}' is required" );
                return false;
            }

            // Skip validation if not required and empty
            if (!$rules['required'] && empty($value)) {
                continue;
            }

            // Type-specific validation
            switch ($rules['type']) {
                case 'email':
                    $sanitized = sanitize_email($value);
                    if (!is_email($sanitized)) {
                        $logger = new CQtrLogger();
                        $logger->Error( "Invalid email address for field '{$field}': {$value}" );
                        return false;
                    }
                    break;

                case 'select':
                    $value = sanitize_text_field($value);
                    if (!in_array($value, $rules['allowed'], true)) {
                        $logger = new CQtrLogger();
                        $logger->Error( "Invalid selection for field '{$field}': {$value}" );
                        return false;
                    }
                    break;

                case 'textarea':
                    $value = sanitize_textarea_field($value);
                    
                    // Special validation for IP list (semicolon-separated, supports CIDR)
                    if ($field === 'blocked_ips' || $field === 'manually_blocked_ips' || $field === 'whitelist_ips' || $field === 'trusted_proxy_ips') {
                        if (!empty($value)) {
                            $ips = array_filter(array_map('trim', explode(';', $value)));
                            foreach ($ips as $ip) {
                                if (!self::IsValidIPOrCIDRStatic($ip)) {
                                    $logger = new CQtrLogger();
                                    $logger->Error( "Invalid IP address in '{$field}': {$ip}" );
                                    return false;
                                }
                            }
                        }
                    }
                    break;

                case 'text':
                default:
                    $value = sanitize_text_field($value);
                    if (isset($rules['max_length']) && strlen($value) > $rules['max_length']) {
                        error_log("Field '{$field}' exceeds maximum length");
                        return false;
                    }
                    break;
            }
        }

        return true;
    }

    /**
     * Create settings instance from POST/input data with validation
     * 
     * @param array $inputData POST data or input array
     * @return QutteraSettings|false New instance on success, false on validation error
     */
    public static function CreateFromInput($inputData)
    {
        if (!self::ValidateInput($inputData)) {
            return false;
        }

        $instance = new self();
        if (!$instance->SetFromArray($inputData)) {
            return false;
        }
        
        return $instance;
    }

    /**
     * Load settings instance from POST data (alias for CreateFromInput)
     * 
     * @param array $inputData POST data
     * @return QutteraSettings|false New instance on success, false on validation error
     */
    public static function LoadFromInput($inputData)
    {
        return self::CreateFromInput($inputData);
    }

    // ===== SERIALIZATION =====

    /**
     * Serialize settings to JSON string
     * 
     * @return string JSON serialized settings
     */
    public function ToJSON()
    {
        return json_encode($this->GetAll(), JSON_UNESCAPED_SLASHES);
    }

    /**
     * Serialize settings to PHP serialized string
     * 
     * @return string PHP serialized settings
     */
    public function Serialize()
    {
        return serialize($this->GetAll());
    }

    /**
     * Deserialize from JSON string (instance method)
     * 
     * @param string $json JSON string
     * @return bool True on success, false on failure
     */
    public function LoadFromJSON($json)
    {
        $data = json_decode($json, true);
        if (!is_array($data)) {
            $logger = new CQtrLogger();
            $logger->Error( "LoadFromJSON: Invalid JSON data" );
            return false;
        }
        return $this->SetFromArray($data);
    }

    /**
     * Deserialize from PHP serialized string (instance method)
     * 
     * @param string $serialized PHP serialized string
     * @return bool True on success, false on failure
     */
    public function LoadFromSerialized($serialized)
    {
        $data = unserialize($serialized, ['allowed_classes' => false]);
        if (!is_array($data)) {
            $logger = new CQtrLogger();
            $logger->Error( "LoadFromSerialized: Invalid serialized data" );
            return false;
        }
        return $this->SetFromArray($data);
    }

    // ===== WORDPRESS OPTION STORAGE =====

    /**
     * Save settings to WordPress options (with base64 encoding)
     * 
     * @param string $option_name WordPress option name
     * @param bool $use_json Use JSON format (default) or PHP serialize
     * @return bool Success/failure
     */
    public function Save($option_name = 'quttera_settings_v1', $use_json = true)
    {
        global $wpdb;
        $wpdb->show_errors();

        $logger = new CQtrLogger();
        
        // Resolve IP conflicts before saving (remove blacklisted IPs that are whitelisted or trusted)
        $this->resolve_ip_conflicts();
        
        // Prepare the value
        if ($use_json) {
            $value = $this->ToJSON();
            
            // Check for JSON encoding errors
            if ($value === false || json_last_error() !== JSON_ERROR_NONE) {
                $json_error = json_last_error_msg();
                $logger->Error("JSON encoding error: {$json_error}");
                return false;
            }
        } else {
            $value = $this->Serialize();
        }
        
        $value_length = strlen($value);
        $logger->Info("Attempting to save settings to option '{$option_name}' (format: " . ($use_json ? 'JSON' : 'serialized') . ", size: {$value_length} bytes)");
        
        // Encode to base64 for safe storage
        $encoded_value = base64_encode($value);
        $encoded_length = strlen($encoded_value);
        $logger->Info("Base64 encoded size: {$encoded_length} bytes");
        
        // Check if option exists
        $exists = get_option($option_name) !== false;
        $logger->Info("Option exists: " . ($exists ? 'yes' : 'no'));
        
        // Clear database errors
        $wpdb->last_error = '';
        
        if ($exists) {
            $result = update_option($option_name, $encoded_value,'', false);
        } else {
            $result = add_option($option_name, $encoded_value, '', false);
        }
        
        // Check result and database errors
        if (!$result) {
            $db_error = !empty($wpdb->last_error) ? $wpdb->last_error : 'Unknown error';
            $logger->Error("Save failed. Result: false, DB Error: {$db_error}, Exists: $exists");
            return false;
        }
        
        // Verify the data was saved correctly
        $stored = get_option($option_name);
        if ($stored === false) {
            $logger->Error("Verification failed: option cannot be retrieved after save");
            return false;
        }
        
        if ($stored !== $encoded_value) {
            $stored_length = strlen($stored);
            $logger->Error("Verification failed. Expected length: {$encoded_length}, Stored length: {$stored_length}");
            return false;
        }
        
        $logger->Info("Settings saved successfully to option '{$option_name}' (base64 encoded)");
        return true;
    }

    /**
     * Load settings from WordPress options (decoding base64, instance method)
     * 
     * @param string $option_name WordPress option name
     * @param bool $use_json Use JSON format (default) or PHP serialize
     * @return bool True on success, false on failure
     */
    public function FetchFromOptions($option_name = 'quttera_settings_v1', $use_json = true)
    {
        $logger = new CQtrLogger();
        
        $encoded_value = get_option($option_name);
        
        if (!$encoded_value) {
            $logger->Info("Option '{$option_name}' not found, using defaults");
            return true; // Not an error, just using defaults
        }
        
        // Decode from base64
        $value = base64_decode($encoded_value, true);
        
        if ($value === false) {
            $logger->Error("Base64 decoding failed for option '{$option_name}'");
            return false;
        }
        
        if ($use_json) {
            return $this->LoadFromJSON($value);
        } else {
            return $this->LoadFromSerialized($value);
        }
    }

    // ===== STATIC FACTORY METHODS =====

    /**
     * Create settings from JSON string
     * 
     * @param string $json JSON string
     * @return QutteraSettings|false New instance on success, false on failure
     */
    public static function FromJSON($json)
    {
        $settings = new self();
        if (!$settings->LoadFromJSON($json)) {
            return false;
        }
        return $settings;
    }

    /**
     * Create settings from serialized string
     * 
     * @param string $serialized PHP serialized string
     * @return QutteraSettings|false New instance on success, false on failure
     */
    public static function FromSerialized($serialized)
    {
        $settings = new self();
        if (!$settings->LoadFromSerialized($serialized)) {
            return false;
        }
        return $settings;
    }

    /**
     * Create settings from array
     * 
     * @param array $data Array of settings
     * @return QutteraSettings|false New instance on success, false on failure
     */
    public static function FromArray($data)
    {
        $settings = new self();
        if (!$settings->SetFromArray($data)) {
            return false;
        }
        return $settings;
    }

    /**
     * Load settings from WordPress options (static factory)
     * 
     * @param string $option_name WordPress option name
     * @param bool $use_json Use JSON format
     * @return QutteraSettings|false New instance with loaded values, false on failure
     */
    public static function LoadFromOptions($option_name = 'quttera_settings_v1', $use_json = true)
    {
        $settings = new self();
        $logger = new CQtrLogger();
        if (!$settings->FetchFromOptions($option_name, $use_json)) {
            $logger->Error("LoadFromOptions failed for option '{$option_name}'");
            return false;
        }

        //$logger->Info("Settings loaded successfully from option '{$option_name}' " . print_r($settings->GetAll(), true));
        return $settings;
    }

    // ===== VALIDATION =====

    /**
     * Validate all settings
     * 
     * @return array ['valid' => bool, 'errors' => array]
     */
    public function Validate()
    {
        $errors = [];

        // Validate email
        if (!is_email($this->alert_email)) {
            $errors[] = 'Invalid alert email address';
        }

        // Validate cure mode
        if (!in_array($this->cure_mode, ['on', 'off', 'quarantine'], true)) {
            $errors[] = 'Invalid cure mode';
        }

        // Validate FS integrity mode
        if (!in_array($this->fs_integrity_mode, ['off', 'fix'], true)) {
            $errors[] = 'Invalid file system integrity mode';
        }

        // Validate protection mode
        if (!in_array($this->protection_mode, ['learning', 'bypass', 'operational'], true)) {
            $errors[] = 'Invalid protection mode';
        }

        // Validate scan mode
        if (!in_array($this->scan_mode, [self::SCAN_MODE_NORMAL, self::SCAN_MODE_HEURISTIC], true)) {
            $errors[] = 'Invalid scan mode';
        }

        // Validate IPs
        if (!empty($this->blocked_ips)) {
            $ips = array_filter(array_map('trim', explode("\n", $this->blocked_ips)));
            foreach ($ips as $ip) {
                if (!filter_var($ip, FILTER_VALIDATE_IP)) {
                    $errors[] = "Invalid IP address: {$ip}";
                    break;
                }
            }
        }

        return [
            'valid' => empty($errors),
            'errors' => $errors
        ];
    }

    // ===== UTILITY METHODS =====

    /**
     * Get blocked IPs as array (semicolon-separated storage)
     * 
     * @return array Array of IP addresses
     */
    public function GetBlockedIPsArray()
    {
        if (empty($this->blocked_ips)) {
            return [];
        }
        return array_filter(array_map('trim', explode(';', $this->blocked_ips)));
    }

    /**
     * Check if IP is blocked
     * 
     * @param string $ip IP address to check
     * @return bool True if blocked
     */
    public function IsIPBlocked($ip)
    {
        return in_array($ip, $this->GetBlockedIPsArray(), true);
    }

    /**
     * Add IP to blocked list
     * 
     * @param string $ip IP address
     * @return bool Success/failure
     */
    public function AddBlockedIP($ip)
    {
        if (!filter_var($ip, FILTER_VALIDATE_IP)) {
            return false;
        }

        $ips = $this->GetBlockedIPsArray();
        if (in_array($ip, $ips, true)) {
            return true; // Already exists
        }

        $ips[] = $ip;
        $this->blocked_ips = implode(';', $ips);
        return true;
    }

    /**
     * Remove IP from blocked list
     * 
     * @param string $ip IP address
     * @return bool Success/failure
     */
    public function RemoveBlockedIP($ip)
    {
        $ips = $this->GetBlockedIPsArray();
        $ips = array_filter($ips, function($blocked_ip) use ($ip) {
            return $blocked_ip !== $ip;
        });
        $this->blocked_ips = implode("\n", $ips);
        return true;
    }

    /**
     * Clear all blocked IPs
     */
    public function ClearBlockedIPs()
    {
        $this->blocked_ips = '';
        return $this;
    }
}
?>