<?php
/**
 * VMPFence Real-time User Monitor
 * @since 1.0.0
 * @since 2.0.0 -- Brute Force functionality moved to Brute Force module
 */

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

class VMPFence_User_Monitor {
    
    private $scan_type = 'user_monitor';
    
    public function __construct() {
        $this->init_hooks();
    }
    
    /**
     * Initialize WordPress hooks for real-time monitoring
     * @since 2.0.0 -- check_blocked_ip, monitor_failed_login, block_authentication_if_ip_blocked moved to Brute Force module
     */
    private function init_hooks() {
        // User account events
        add_action('user_register', [$this, 'monitor_user_creation'], 10, 1);
        add_action('profile_update', [$this, 'monitor_user_update'], 10, 3);
        add_action('deleted_user', [$this, 'monitor_user_deletion'], 10, 2);
        
        // User authentication events  
        add_action('wp_login', [$this, 'monitor_successful_login'], 10, 2);
        add_action('wp_logout', [$this, 'monitor_logout'], 10, 1);
        add_action('after_password_reset', [$this, 'monitor_password_reset'], 10, 2);
        
        // User role/permission events
        add_action('add_user_role', [$this, 'monitor_role_added'], 10, 2);
        add_action('remove_user_role', [$this, 'monitor_role_removed'], 10, 2);
        add_action('set_user_role', [$this, 'monitor_role_change'], 10, 3);
        
        // WordPress options monitoring
        add_action('update_option_admin_email', [$this, 'monitor_admin_email_change'], 10, 3);
        add_action('update_option_siteurl', [$this, 'monitor_siteurl_change'], 10, 3);
        add_action('update_option_home', [$this, 'monitor_home_url_change'], 10, 3);
        add_action('update_option_users_can_register', [$this, 'monitor_registration_setting'], 10, 3);
        add_action('update_option_default_role', [$this, 'monitor_default_role_change'], 10, 3);
        add_action('update_option_active_plugins', [$this, 'monitor_active_plugins_change'], 10, 3);
    }
    
    /**
     * Monitor new user creation
     */
    public function monitor_user_creation($user_id) {
        $user = get_user_by('ID', $user_id);
        
        // Check if new admin user
        if (in_array('administrator', $user->roles)) {
            $this->log_security_event('new_admin_user', [
                'user_id' => $user_id,
                'username' => $user->user_login,
                'email' => $user->user_email,
                'roles' => $user->roles,
                'severity' => 'high',
                'immediate_alert' => true
            ]);
        }
        
        // Check username patterns
        if ($this->is_suspicious_username($user->user_login)) {
            $this->log_security_event('suspicious_username', [
                'user_id' => $user_id,
                'username' => $user->user_login,
                'severity' => 'medium'
            ]);
        }
        
        // Log general user creation
        $this->log_security_event('user_created', [
            'user_id' => $user_id,
            'username' => $user->user_login,
            'email' => $user->user_email,
            'roles' => $user->roles,
            'severity' => 'info'
        ]);
    }
    
    /**
     * Monitor user profile updates
     */
    public function monitor_user_update($user_id, $old_user_data, $userdata) {
        $user = get_user_by('ID', $user_id);
        
        // Check for significant changes
        $changes = [];
        
        // Check email change
        if (isset($userdata['user_email']) && $old_user_data->user_email !== $userdata['user_email']) {
            $changes['email'] = [
                'old' => $old_user_data->user_email,
                'new' => $userdata['user_email']
            ];
        }
        
        // Check password change
        if (isset($userdata['user_pass']) && !empty($userdata['user_pass'])) {
            $changes['password'] = true;
        }
        
        // Check username change (rare but possible)
        if (isset($userdata['user_login']) && $old_user_data->user_login !== $userdata['user_login']) {
            $changes['username'] = [
                'old' => $old_user_data->user_login,
                'new' => $userdata['user_login']
            ];
        }
        
        // Check role changes
        if (isset($userdata['role']) && !in_array($userdata['role'], $old_user_data->roles)) {
            $changes['role'] = [
                'old' => $old_user_data->roles,
                'new' => $userdata['role']
            ];
        }
        
        // Determine severity based on changes
        $severity = 'info';
        $immediate_alert = false;
        
        if (!empty($changes['email']) || !empty($changes['username']) || !empty($changes['role'])) {
            $severity = 'medium';
        }
        
        if (!empty($changes['role']) && ($userdata['role'] === 'administrator' || in_array('administrator', $old_user_data->roles))) {
            $severity = 'high';
            $immediate_alert = true;
        }
        
        // Log the update event
        $this->log_security_event('user_updated', [
            'user_id' => $user_id,
            'username' => $user->user_login,
            'changes' => $changes,
            'severity' => $severity,
            'immediate_alert' => $immediate_alert
        ]);
    }
    
    /**
     * Monitor user deletion
     */
    public function monitor_user_deletion($user_id, $reassign) {
        // Note: User is already deleted at this point, so we need to use the passed user_id
        $this->log_security_event('user_deleted', [
            'user_id' => $user_id,
            'reassign_to' => $reassign,
            'severity' => 'medium',
            'immediate_alert' => true
        ]);
    }
    
    /**
     * Monitor successful logins
     */
    public function monitor_successful_login($user_login, $user) {
        $this->log_security_event('successful_login', [
            'user_id' => $user->ID,
            'username' => $user_login,
            'ip_address' => $this->get_client_ip(),
            'user_agent' => sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'] ?? '')),
            'roles' => $user->roles,
            'severity' => 'info'
        ]);
    }
    
    /**
     * Monitor user logouts
     */
    public function monitor_logout($user_id = null) {
        // Handle cases where user_id might not be passed
        if (!$user_id) {
            $user_id = get_current_user_id();
        }
        
        $user = get_user_by('ID', $user_id);
        if ($user) {
            $this->log_security_event('user_logout', [
                'user_id' => $user_id,
                'username' => $user->user_login,
                'ip_address' => $this->get_client_ip(),
                'user_agent' => sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'] ?? '')),
                'roles' => $user->roles,
                'severity' => 'info'
            ]);
        }
    }
    
    /**
     * Monitor role changes
     */
    public function monitor_role_added($user_id, $new_role) {
        $user = get_user_by('ID', $user_id);
        $severity = ($new_role === 'administrator') ? 'high' : 'medium';
        
        $this->log_security_event('role_added', [
            'user_id' => $user_id,
            'username' => $user->user_login,
            'role_added' => $new_role,
            'current_roles' => $user->roles,
            'severity' => $severity,
            'immediate_alert' => ($new_role === 'administrator')
        ]);
    }
    
    /**
     * Monitor role removed
     */
    public function monitor_role_removed($user_id, $old_role) {
        $user = get_user_by('ID', $user_id);
        $severity = ($old_role === 'administrator') ? 'high' : 'medium';
        
        $this->log_security_event('role_removed', [
            'user_id' => $user_id,
            'username' => $user->user_login,
            'role_removed' => $old_role,
            'current_roles' => $user->roles,
            'severity' => $severity,
            'immediate_alert' => ($old_role === 'administrator')
        ]);
    }
    
    /**
     * Monitor role change (set_user_role action)
     */
    public function monitor_role_change($user_id, $new_role, $old_roles) {
        $user = get_user_by('ID', $user_id);
        $severity = ($new_role === 'administrator' || in_array('administrator', $old_roles)) ? 'high' : 'medium';
        
        $this->log_security_event('role_changed', [
            'user_id' => $user_id,
            'username' => $user->user_login,
            'new_role' => $new_role,
            'old_roles' => $old_roles,
            'current_roles' => $user->roles,
            'severity' => $severity,
            'immediate_alert' => ($new_role === 'administrator' || in_array('administrator', $old_roles))
        ]);
    }
    
    /**
     * Monitor WordPress option changes
     */
    public function monitor_admin_email_change($old_value, $new_value, $option) {
        $this->log_security_event('admin_email_changed', [
            'old_email' => $old_value,
            'new_email' => $new_value,
            'severity' => 'high',
            'immediate_alert' => true
        ]);
    }
    
    /**
     * Monitor active plugins changes
     * @since 2.2.2 - Avoid logging if tables are being deleted on deactivation
     */
    public function monitor_active_plugins_change($old_value, $new_value, $option) {
        // Calculate differences
        $old_plugins = is_array($old_value) ? $old_value : [];
        $new_plugins = is_array($new_value) ? $new_value : [];
        
        $activated = array_diff($new_plugins, $old_plugins);
        $deactivated = array_diff($old_plugins, $new_plugins);
        
        if (!empty($activated)) {
            foreach ($activated as $plugin) {
                $this->log_security_event('plugin_activated', [
                    'plugin' => $plugin,
                    'severity' => 'medium',
                    'immediate_alert' => true
                ]);
            }
        }
        
        if (!empty($deactivated)) {
            // Check if deactivation choice is enabled and user chose to delete all tables
            $enable_deactivation_choice = get_option('vmpfence_enable_deactivation_choice', 0);
            if ($enable_deactivation_choice) {
                $data_action = get_transient('vmpfence_deactivation_data_action');
                if ($data_action === 'delete') {
                    return; // Skip logging when deleting all tables
                }
            }
            
            foreach ($deactivated as $plugin) {
                $this->log_security_event('plugin_deactivated', [
                    'plugin' => $plugin,
                    'severity' => 'medium'
                ]);
            }
        }
    }
    
    
    /**
     * Log security event to database
     * @since 2.2.2 - Avoid logging if tables are being deleted on deactivation
     */
    private function log_security_event($event_type, $data) {
        global $wpdb;
        
        $table = $wpdb->prefix . 'vmpfence_events';
        
        // Check if we're deleting tables during deactivation
        $enable_deactivation_choice = get_option('vmpfence_enable_deactivation_choice', 0);
        if ($enable_deactivation_choice) {
            $data_action = get_transient('vmpfence_deactivation_data_action');
            if ($data_action === 'delete') {
                return; // Skip logging when deleting all tables during deactivation
            }
        }
        
        // Ensure table exists before inserting (self-healing)
        $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table));
        if ($table_exists !== $table) {
            // Table missing - recreate it
            if (class_exists('VMPFence_Database')) {
                VMPFence_Database::ensure_events_table_exists();
            }
        }
        
        // Get current user info
        $current_user = wp_get_current_user();
        $user_id = $current_user->ID ?: null;
        $username = $current_user->user_login ?: null;
        
        // Convert severity text to number
        $severity = $data['severity'] ?? 'medium';
        $severity_num = $this->map_severity_to_number($severity);
        
        // Get client IP and convert to binary
        $source_ip = $this->get_client_ip();
        $ip_binary = null;
        if ($source_ip && filter_var($source_ip, FILTER_VALIDATE_IP)) {
            $ip_binary = inet_pton($source_ip);
        }
        
        // Generate a descriptive message
        $message = $this->generate_event_message($event_type, $data);
        
        $result = $wpdb->insert($table, [
            'time' => time(), // Store as UNIX timestamp
            'event_type' => $event_type,
            'severity' => $severity_num,
            'source_ip' => $ip_binary,
            'user_id' => $user_id,
            'username' => $username,
            'message' => $message,
            'data' => json_encode($data)
        ], [
            '%d', '%s', '%d', '%s', '%d', '%s', '%s', '%s'
        ]);
        
        // if ($result === false) {
        //     // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional for debugging
        //     error_log('VMPFence: Failed to log security event: ' . $wpdb->last_error);
        // }
        
        // Send immediate alert if flagged
        if (!empty($data['immediate_alert'])) {
            $this->send_immediate_alert($event_type, $data);
        }
    }
    
    /**
     * Check if username matches suspicious patterns
     */
    private function is_suspicious_username($username) {
        $suspicious_patterns = [
            'admin', 'administrator', 'root', 'test', 'demo', 'guest',
            'user', 'manager', 'support', 'service', 'operator'
        ];
        
        return in_array(strtolower($username), $suspicious_patterns);
    }
    
    /**
     * Get client IP address
     */
    private function get_client_ip() {
        $headers = [
            'HTTP_CF_CONNECTING_IP',
            'HTTP_X_FORWARDED_FOR', 
            'HTTP_X_FORWARDED',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR'
        ];
        
        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $ip = sanitize_text_field(wp_unslash($_SERVER[$header]));
                if (strpos($ip, ',') !== false) {
                    $ip = explode(',', $ip)[0];
                }
                return trim($ip);
            }
        }
        
        return '0.0.0.0';
    }
    
    /**
     * Send immediate security alert
     */
    private function send_immediate_alert($event_type, $data) {
        // Implementation for immediate alerts (email, etc.)
        // This would integrate with existing VMPFence notification system
    }
    
    /**
     * Map severity text to number for database storage
     */
    private function map_severity_to_number($severity_text) {
        switch (strtolower($severity_text)) {
            case 'info': return 0;
            case 'low': return 1;
            case 'medium': return 2;
            case 'high': return 3;
            case 'critical': return 4;
            default: return 2; // Default to medium
        }
    }
    
    /**
     * Generate a descriptive message for the event
     */
    private function generate_event_message($event_type, $data) {
        switch ($event_type) {
            case 'new_admin_user':
                $username = isset($data['username']) ? $data['username'] : 'unknown user';
                return "New administrator user '{$username}' was created";
            case 'suspicious_username':
                $username = isset($data['username']) ? $data['username'] : 'unknown user';
                return "Suspicious username '{$username}' detected during registration";
            case 'user_created':
                $username = isset($data['username']) ? $data['username'] : 'unknown user';
                return "New user '{$username}' registered";
            case 'user_updated':
                $username = isset($data['username']) ? $data['username'] : 'unknown user';
                $changes = isset($data['changes']) ? $data['changes'] : [];
                $change_list = [];
                
                if (isset($changes['email'])) {
                    $change_list[] = 'email';
                }
                if (isset($changes['password'])) {
                    $change_list[] = 'password';
                }
                if (isset($changes['username'])) {
                    $change_list[] = 'username';
                }
                if (isset($changes['role'])) {
                    $change_list[] = 'role';
                }
                
                $change_text = !empty($change_list) ? ' (' . implode(', ', $change_list) . ' changed)' : '';
                return "User '{$username}' profile updated{$change_text}";
            case 'user_deleted':
                $user_id = isset($data['user_id']) ? $data['user_id'] : 'unknown';
                return "User ID {$user_id} was deleted";
            case 'failed_login':
                $username = isset($data['username']) ? $data['username'] : 'unknown user';
                return "Failed login attempt for user '{$username}'";
            case 'successful_login':
                $username = isset($data['username']) ? $data['username'] : 'unknown user';
                return "User '{$username}' logged in successfully";
            case 'role_added':
                $role = isset($data['role_added']) ? $data['role_added'] : 'unknown';
                $username = isset($data['username']) ? $data['username'] : 'unknown user';
                return "Role '{$role}' added to user '{$username}'";
            case 'role_removed':
                $role = isset($data['role_removed']) ? $data['role_removed'] : 'unknown';
                $username = isset($data['username']) ? $data['username'] : 'unknown user';
                return "Role '{$role}' removed from user '{$username}'";
            case 'role_changed':
                $new_role = isset($data['new_role']) ? $data['new_role'] : 'unknown';
                $old_roles = isset($data['old_roles']) ? implode(', ', $data['old_roles']) : 'unknown';
                $username = isset($data['username']) ? $data['username'] : 'unknown user';
                return "User '{$username}' role changed from '{$old_roles}' to '{$new_role}'";
            case 'admin_email_changed':
                $old_email = isset($data['old_email']) ? $data['old_email'] : 'unknown';
                $new_email = isset($data['new_email']) ? $data['new_email'] : 'unknown';
                return "Admin email changed from '{$old_email}' to '{$new_email}'";
            case 'plugin_activated':
                $plugin = isset($data['plugin']) ? $data['plugin'] : 'unknown plugin';
                return "Plugin '{$plugin}' was activated";
            case 'plugin_deactivated':
                $plugin = isset($data['plugin']) ? $data['plugin'] : 'unknown plugin';
                return "Plugin '{$plugin}' was deactivated";
            case 'brute_force_detected':
                $attempts = $data['attempts_24h'] ?? $data['attempts_1h'] ?? $data['attempts'] ?? 'unknown';
                $ip = isset($data['ip']) ? $data['ip'] : 'unknown IP';
                return "Brute force attack detected from IP {$ip} ({$attempts} attempts)";
            default:
                return "Security event: {$event_type}";
        }
    }
}
