<?php
if (!defined('ABSPATH')) {
    exit;
}

//Added by Moe - Oct 2025
function moesec_base32_encode($data) {
    $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
    $output = '';
    
    for ($i = 0; $i < strlen($data); $i++) {
        $output .= $alphabet[ord($data[$i]) >> 3];
        $output .= $alphabet[(ord($data[$i]) & 0x07) << 2 | (ord($data[$i + 1]) >> 6)];
        if (++$i >= strlen($data)) break;
        $output .= $alphabet[(ord($data[$i]) & 0x3E) >> 1];
        $output .= $alphabet[(ord($data[$i]) & 0x01) << 4 | (ord($data[$i + 1]) >> 4)];
        if (++$i >= strlen($data)) break;
        $output .= $alphabet[(ord($data[$i]) & 0x0F) << 1 | (ord($data[$i + 1]) >> 7)];
        if (++$i >= strlen($data)) break;
        $output .= $alphabet[(ord($data[$i]) & 0x7C) >> 2];
        $output .= $alphabet[(ord($data[$i]) & 0x03) << 3 | (ord($data[$i + 1]) >> 5)];
        if (++$i >= strlen($data)) break;
        $output .= $alphabet[ord($data[$i]) & 0x1F];
    }
    
    return $output;
}

function moesec_base32_decode($input) {
    $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
    $input = strtoupper($input);
    $input = preg_replace('/[^A-Z2-7]/', '', $input);
    
    $output = '';
    $buffer = 0;
    $bits = 0;
    
    for ($i = 0; $i < strlen($input); $i++) {
        $buffer = ($buffer << 5) | strpos($alphabet, $input[$i]);
        $bits += 5;
        
        if ($bits >= 8) {
            $bits -= 8;
            $output .= chr(($buffer >> $bits) & 0xFF);
        }
    }
    
    return $output;
}

function moesec_totp_generate($secret) {
    $time_slot = floor(time() / 30);
    
    $key = moesec_base32_decode($secret);
    if (!$key) return '000000';
    
    $time_binary = '';
    for ($i = 7; $i >= 0; $i--) {
        $time_binary .= chr(($time_slot >> ($i * 8)) & 0xFF);
    }
    
    $hash = hash_hmac('sha1', $time_binary, $key, true);
    
    $offset = ord(substr($hash, -1)) & 0x0F;
    
    $code = (
        ((ord($hash[$offset]) & 0x7F) << 24) |
        (ord($hash[$offset + 1]) << 16) |
        (ord($hash[$offset + 2]) << 8) |
        ord($hash[$offset + 3])
    );
    
    return str_pad($code % 1000000, 6, '0', STR_PAD_LEFT);
}

function moesec_totp_verify($secret, $code) {
    $code = preg_replace('/[^0-9]/', '', $code);
    if (strlen($code) !== 6) return false;
    
    for ($i = -1; $i <= 1; $i++) {
        $time_slot = floor(time() / 30) + $i;
        
        $key = moesec_base32_decode($secret);
        if (!$key) continue;
        
        $time_binary = '';
        for ($j = 7; $j >= 0; $j--) {
            $time_binary .= chr(($time_slot >> ($j * 8)) & 0xFF);
        }
        
        $hash = hash_hmac('sha1', $time_binary, $key, true);
        
        $offset = ord(substr($hash, -1)) & 0x0F;
        
        $expected_code = (
            ((ord($hash[$offset]) & 0x7F) << 24) |
            (ord($hash[$offset + 1]) << 16) |
            (ord($hash[$offset + 2]) << 8) |
            ord($hash[$offset + 3])
        );
        
        $expected_code = str_pad($expected_code % 1000000, 6, '0', STR_PAD_LEFT);
        
        if ($expected_code === $code) {
            return true;
        }
    }
    
    return false;
}

function moesec_generate_secret() {
    $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
    $secret = '';
    
    for ($i = 0; $i < 16; $i++) {
        $secret .= $chars[wp_rand(0, 31)];
    }
    
    return $secret;
}

// ============================================================================
// ROLE-BASED 2FA ENFORCEMENT FUNCTIONS
// ============================================================================

/**
 * Check if 2FA is forced for a specific user
 */
function moesec_is_2fa_forced_for_user($user_id) {
    $user = get_userdata($user_id);
    if (!$user) return false;
    
    // Check if 2FA is forced for all users
    if (get_option('moesec_force_2fa_all_users', false)) {
        return true;
    }
    
    // Check if 2FA is forced for any of the user's roles
    $forced_roles = get_option('moesec_force_2fa_roles', array());
    if (!is_array($forced_roles)) {
        $forced_roles = array();
    }
    
    foreach ($user->roles as $role) {
        if (in_array($role, $forced_roles)) {
            return true;
        }
    }
    
    return false;
}

/**
 * Check if a user can disable 2FA
 */
function moesec_can_user_disable_2fa($user_id) {
    $user = get_userdata($user_id);
    if (!$user) return true;
    
    // If 2FA is forced for this user, they cannot disable it
    if (moesec_is_2fa_forced_for_user($user_id)) {
        return false;
    }
    
    // Check if specific roles are restricted from disabling 2FA
    $restricted_roles = get_option('moesec_restrict_2fa_disable_roles', array());
    if (!is_array($restricted_roles)) {
        $restricted_roles = array();
    }
    
    foreach ($user->roles as $role) {
        if (in_array($role, $restricted_roles)) {
            return false;
        }
    }
    
    return true;
}

/**
 * Get allowed 2FA methods for a user
 */
function moesec_get_allowed_2fa_methods($user_id = null) {
    $allowed_methods = get_option('moesec_allowed_2fa_methods', array('email', 'google_auth'));
    
    if (!is_array($allowed_methods) || empty($allowed_methods)) {
        $allowed_methods = array('email', 'google_auth');
    }
    
    return $allowed_methods;
}

// ============================================================================
// GLOBAL DISABLE FUNCTIONALITY
// ============================================================================

function moesec_deactivate_all_users_2fa() {
    global $wpdb;
    
    // Delete all user meta records for 2FA enabled status
    $result = $wpdb->delete(
        $wpdb->usermeta,
        array('meta_key' => 'moesec_2fa_enabled'),
        array('%s')
    );
    
    // Also clear any email codes and timestamps
    $wpdb->delete(
        $wpdb->usermeta,
        array('meta_key' => '_moesec_email_code'),
        array('%s')
    );
    
    $wpdb->delete(
        $wpdb->usermeta,
        array('meta_key' => '_moesec_email_time'),
        array('%s')
    );
    
    // Clear any email sent transients
    $users = get_users(array(
        'meta_key' => 'moesec_2fa_enabled',
        'meta_value' => '1',
        'fields' => 'ID'
    ));
    
    foreach ($users as $user_id) {
        delete_transient("moesec_recent_email_{$user_id}");
    }
    
    return $result;
}

// ============================================================================
// EMAIL 2FA - WITH DUPLICATE PROTECTION
// ============================================================================

function moesec_send_email_code($user) {
    global $wpdb;
    
    // CHECK FOR RECENT EMAIL FIRST - PREVENT DUPLICATES
    $recent_email_flag = get_transient("moesec_recent_email_{$user->ID}");
    if ($recent_email_flag) {
        return new WP_Error(
            '2fa_required', 
            '<strong>✓ Verification Code Sent</strong><br>Please check your email for the 6-digit verification code.'
        );
    }
    
    $code = sprintf('%06d', random_int(0, 999999));
    $time = time();
    
    // METHOD 1: Direct database insertion
    // Delete any existing codes first
    $wpdb->delete($wpdb->usermeta, array(
        'user_id' => $user->ID,
        'meta_key' => '_moesec_email_code'
    ));
    
    $wpdb->delete($wpdb->usermeta, array(
        'user_id' => $user->ID,
        'meta_key' => '_moesec_email_time'
    ));
    
    // Insert new codes
    $result1 = $wpdb->insert($wpdb->usermeta, array(
        'user_id' => $user->ID,
        'meta_key' => '_moesec_email_code',
        'meta_value' => $code
    ), array('%d', '%s', '%s'));
    
    $result2 = $wpdb->insert($wpdb->usermeta, array(
        'user_id' => $user->ID,
        'meta_key' => '_moesec_email_time',
        'meta_value' => $time
    ), array('%d', '%s', '%d'));
    
    // METHOD 2: WordPress functions as backup
    if (!$result1 || !$result2) {
        update_user_meta($user->ID, '_moesec_email_code', $code);
        update_user_meta($user->ID, '_moesec_email_time', $time);
    }
    
    // VERIFY STORAGE
    $stored_code = get_user_meta($user->ID, '_moesec_email_code', true);
    $stored_time = get_user_meta($user->ID, '_moesec_email_time', true);
    
    // SET FLAG TO PREVENT DUPLICATE EMAILS FOR 2 MINUTES
    set_transient("moesec_recent_email_{$user->ID}", true, 120);
    
    // SEND EMAIL - FORCE WITH PROPER HEADERS
    $to = $user->user_email;
    $subject = 'Your Login Verification Code - ' . get_bloginfo('name');
    $message = "Hello {$user->display_name},\n\nYour login verification code is:\n\n{$code}\n\nThis code will expire in 15 minutes.\n\nIf you didn't request this code, please ignore this email.\n\nThank you,\n" . get_bloginfo('name') . " - Powered by MoeSec.com Website Security";
    
    // Set proper email headers
    $headers = array(
        'From: ' . get_bloginfo('name') . ' <' . get_option('admin_email') . '>',
        'Content-Type: text/plain; charset=UTF-8'
    );
    
    // Force email content type
    add_filter('wp_mail_content_type', function() {
        return 'text/plain';
    });
    
    add_filter('wp_mail_from', function($from_email) {
        return get_option('admin_email');
    });
    
    add_filter('wp_mail_from_name', function($from_name) {
        return get_bloginfo('name');
    });
    
    $email_sent = wp_mail($to, $subject, $message, $headers);
    
    // Remove filters
    remove_filter('wp_mail_content_type', 'moesec_mail_content_type');
    remove_filter('wp_mail_from', 'moesec_mail_from');
    remove_filter('wp_mail_from_name', 'moesec_mail_from_name');
    
    // Return the appropriate response
    if ($stored_code === $code) {
        if ($email_sent) {
            return new WP_Error(
                '2fa_required',
                '<strong>✓ Verification Code Sent</strong><br>We sent a 6-digit code to your email address. Please check your inbox and enter the code below.'
            );
        } else {
            return new WP_Error(
                '2fa_required', 
                '<strong>✓ Enter Verification Code</strong><br>Please check your email at ' . $user->user_email . ' for the 6-digit verification code. (Email delivery may be delayed)'
            );
        }
    } else {
        return new WP_Error(
            '2fa_error',
            '<strong>⚠ System Error</strong><br>Unable to generate verification code. Please try again.'
        );
    }
}

// ============================================================================
// USER PROFILE FIELDS
// ============================================================================

add_action('show_user_profile', 'moesec_2fa_profile_fields');
add_action('edit_user_profile', 'moesec_2fa_profile_fields');

function moesec_2fa_profile_fields($user) {
    if (!current_user_can('edit_user', $user->ID)) return;
    if (!get_option('moesec_enable_2fa', false)) return;
    
    $enabled = get_user_meta($user->ID, 'moesec_2fa_enabled', true);
    $method = get_user_meta($user->ID, 'moesec_2fa_method', true) ?: 'email';
    $secret = get_user_meta($user->ID, 'moesec_2fa_secret', true);
    
    $is_forced = moesec_is_2fa_forced_for_user($user->ID);
    $can_disable = moesec_can_user_disable_2fa($user->ID);
    $allowed_methods = moesec_get_allowed_2fa_methods($user->ID);
    
    if (empty($secret)) {
        $secret = moesec_generate_secret();
        update_user_meta($user->ID, 'moesec_2fa_secret', $secret);
    }
    
    $current_code = moesec_totp_generate($secret);
    ?>
    <h3>🔐 MoeSec Two-Factor Authentication</h3>
    
    <!-- Display forced 2FA status -->
    <?php if ($is_forced): ?>
    <div style="background: #fff3cd; border: 1px solid #ffc107; padding: 12px; margin-bottom: 15px; border-radius: 4px;">
        <p style="margin: 0; color: #856404;"><strong>⚠️ 2FA is required for your role</strong> - You cannot disable this feature.</p>
    </div>
    <?php endif; ?>
    
    <table class="form-table">
        <tr>
            <th><label for="moesec_2fa_enabled">Enable 2FA</label></th>
            <td>
                <!-- Disable checkbox if 2FA is forced or user cannot disable it -->
                <input type="checkbox" name="moesec_2fa_enabled" id="moesec_2fa_enabled" value="1" <?php checked($enabled, 1); ?> <?php echo ($is_forced || !$can_disable) ? 'disabled' : ''; ?>>
                <label for="moesec_2fa_enabled">Enable two-factor authentication</label>
                <?php if ($is_forced): ?>
                    <p class="description" style="color: #d63638;"><strong>Required:</strong> 2FA is mandatory for your role.</p>
                <?php elseif (!$can_disable && $enabled): ?>
                    <p class="description" style="color: #d63638;"><strong>Locked:</strong> Your role does not allow disabling 2FA once enabled.</p>
                <?php else: ?>
                    <p class="description">Enable two-factor authentication for enhanced security.</p>
                <?php endif; ?>
            </td>
        </tr>
        <tr>
            <th><label for="moesec_2fa_method">2FA Method</label></th>
            <td>
                <select name="moesec_2fa_method" id="moesec_2fa_method" <?php echo ($is_forced || !$can_disable) ? 'disabled' : ''; ?>>
                    <?php if (in_array('email', $allowed_methods)): ?>
                        <option value="email" <?php selected($method, 'email'); ?>>📧 Email Code</option>
                    <?php endif; ?>
                    <?php if (in_array('google_auth', $allowed_methods)): ?>
                        <option value="google_auth" <?php selected($method, 'google_auth'); ?>>📱 Google Authenticator</option>
                    <?php endif; ?>
                </select>

                <p><strong>**If you select Google Auth method, The QR code can be found below after saving first.</strong></p>

            </td>

        </tr>
        <?php if ($method === 'google_auth' && $enabled): ?>
        <tr>
            <th>Authenticator Setup</th>
            <td>
                <div style="background: #fff; border: 2px solid #0073aa; padding: 30px; border-radius: 8px; width: 60%;">
                    
                    <div style="background: #fff3cd; border: 2px solid #ffc107; padding: 20px; margin-bottom: 30px; border-radius: 5px;">
                        <h3 style="margin: 0 0 15px 0; color: #856404;">⚠️ IMPORTANT SETUP STEPS</h3>
                        <ol style="margin: 0; padding-left: 20px; color: #856404; line-height: 1.8;">
                            <li><strong>DELETE</strong> any existing entry in Google Authenticator</li>
                            <li><strong>Scan the QR code</strong></li>
                        </ol>
                    </div>
                    
                    <h3>Download App</h3>
                    <p>
                        <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2" target="_blank" class="button button-primary">Android</a>
                        <a href="https://apps.apple.com/app/google-authenticator/id388497605" target="_blank" class="button button-primary">iOS</a>
                    </p><br>

                    <p><strong>Current Code:</strong> <code style="font-size: 20px;"><?php echo $current_code; ?></code></p><br>
                    
                    <?php
                    $qr_url = 'https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=' . urlencode('otpauth://totp/' . urlencode(get_bloginfo('name')) . ':' . urlencode($user->user_email) . '?secret=' . $secret . '&issuer=' . urlencode(get_bloginfo('name')));
                    echo '<img src="' . esc_url($qr_url) . '" alt="QR Code" style="border: 1px solid #ccc; padding: 10px; background: white;">';
                    ?>
                </div>
            </td>
        </tr>
        <?php endif; ?>
    </table>
    
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        var checkbox = document.getElementById('moesec_2fa_enabled');
        var methodRow = document.getElementById('moesec_2fa_method').closest('tr');
        
        function toggleMethodRow() {
            methodRow.style.display = checkbox.checked ? '' : 'none';
        }
        
        checkbox.addEventListener('change', toggleMethodRow);
        toggleMethodRow(); // Initial state
    });
    </script>
    <?php
}

add_action('personal_options_update', 'moesec_save_2fa_settings');
add_action('edit_user_profile_update', 'moesec_save_2fa_settings');

function moesec_save_2fa_settings($user_id) {
    if (!current_user_can('edit_user', $user_id)) return;
    
    $can_disable = moesec_can_user_disable_2fa($user_id);
    $is_forced = moesec_is_2fa_forced_for_user($user_id);
    
    // If 2FA is forced or user cannot disable it, force it to be enabled
    if ($is_forced) {
        update_user_meta($user_id, 'moesec_2fa_enabled', 1);
    } else {
        update_user_meta($user_id, 'moesec_2fa_enabled', isset($_POST['moesec_2fa_enabled']) ? 1 : 0);
    }
    
    if (isset($_POST['moesec_2fa_method'])) {
        $method = sanitize_text_field($_POST['moesec_2fa_method']);
        $allowed_methods = moesec_get_allowed_2fa_methods($user_id);
        
        // Only save if method is allowed
        if (in_array($method, $allowed_methods)) {
            update_user_meta($user_id, 'moesec_2fa_method', $method);
        }
    }
}

// ============================================================================
// LOGIN INTEGRATION 
// ============================================================================

// Add 2FA field to login form
add_action('login_form', 'moesec_login_2fa_field');
function moesec_login_2fa_field() {
    if (!get_option('moesec_enable_2fa', false)) return;
    
    $show_field = false;
    global $errors;
    if (is_wp_error($errors)) {
        $error_codes = $errors->get_error_codes();
        if (in_array('2fa_required', $error_codes) || in_array('2fa_invalid', $error_codes) || in_array('2fa_expired', $error_codes)) {
            $show_field = true;
        }
    }
    ?>
    
    <div id="moesec-2fa-container" style="<?php echo $show_field ? '' : 'display: none;'; ?> margin-top: 15px; padding: 15px; background: #f0f7ff; border-left: 4px solid #0073aa; border-radius: 4px;">
        <p style="margin: 0 0 10px 0; color: #0073aa; font-weight: bold;">🔐 MoeSec Two-Factor Authentication Required</p>
        <p id="moesec-method-text" style="margin: 0 0 15px 0; color: #0073aa;">
            <?php echo $show_field ? 'A 6-digit code has been sent to your email address.' : ''; ?>
        </p>
        
        <p>
            <label for="two_factor_code" style="font-weight: bold; display: block; margin-bottom: 5px;">6-Digit Verification Code</label>
            <input type="text" 
                   name="two_factor_code" 
                   id="two_factor_code" 
                   class="input" 
                   value="" 
                   size="20" 
                   autocomplete="one-time-code" 
                   placeholder="000000" 
                   style="font-size: 24px; text-align: center; letter-spacing: 8px; font-family: monospace; font-weight: bold; width: 100%; padding: 12px;">
        </p>
    </div>

    <script>
    document.addEventListener('DOMContentLoaded', function() {
        
        var container = document.getElementById('moesec-2fa-container');
        var codeInput = document.getElementById('two_factor_code');
        var methodText = document.getElementById('moesec-method-text');
        var usernameInput = document.getElementById('user_login');
        var passwordInput = document.getElementById('user_pass');
        
        // Function to show 2FA fields
        function show2FAFields(method) {
            
            // Update method text
            if (method === 'email') {
                methodText.textContent = 'A 6-digit code has been sent to your email address.';
            } else {
                methodText.textContent = 'Enter the 6-digit code from your authenticator app.';
            }
            
            // Show container
            container.style.display = 'block';
            container.style.opacity = '0';
            container.style.transform = 'translateY(-10px)';
            
            // Animate in
            setTimeout(function() {
                container.style.transition = 'all 0.3s ease';
                container.style.opacity = '1';
                container.style.transform = 'translateY(0)';
            }, 10);
            
            // Focus on code input
            setTimeout(function() {
                if (codeInput) {
                    codeInput.focus();
                    codeInput.select();
                }
            }, 400);
        }
        
        // Function to hide 2FA fields
        function hide2FAFields() {
            if (container) {
                container.style.display = 'none';
            }
        }
        
        // Function to check 2FA status
        function check2FAStatus(username) {
            if (!username || username.trim().length < 1) {
                hide2FAFields();
                return;
            }
            
            // Create AJAX request
            var xhr = new XMLHttpRequest();
            xhr.open('POST', '<?php echo admin_url('admin-ajax.php'); ?>', true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            
            xhr.onload = function() {
                if (xhr.status === 200) {
                    try {
                        var response = JSON.parse(xhr.responseText);
                        
                        if (response.success && response.data.enabled) {
                            show2FAFields(response.data.method);
                            
                            // If email method, send the code via separate AJAX call
                            if (response.data.method === 'email') {
                                sendEmailCode(username);
                            }
                        } else {
                            hide2FAFields();
                        }
                    } catch (e) {
                        console.error('MOESEC 2FA: JSON parse error:', e);
                        hide2FAFields();
                    }
                } else {
                    console.error('MOESEC 2FA: AJAX error:', xhr.status);
                    hide2FAFields();
                }
            };
            
            xhr.onerror = function() {
                console.error('MOESEC 2FA: AJAX request failed');
                hide2FAFields();
            };
            
            var data = 'action=moesec_check_2fa_status&username=' + encodeURIComponent(username) + '&nonce=<?php echo wp_create_nonce('moesec_2fa_nonce'); ?>';
            xhr.send(data);
        }
        
        // Function to send email code via AJAX
        function sendEmailCode(username) {
            
            var xhr = new XMLHttpRequest();
            xhr.open('POST', '<?php echo admin_url('admin-ajax.php'); ?>', true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            
            xhr.onload = function() {
                if (xhr.status === 200) {
                    try {
                        var response = JSON.parse(xhr.responseText);
                    } catch (e) {
                        console.error('MOESEC 2FA: Email code JSON parse error:', e);
                    }
                }
            };
            
            var data = 'action=moesec_send_email_code&username=' + encodeURIComponent(username) + '&nonce=<?php echo wp_create_nonce('moesec_2fa_nonce'); ?>';
            xhr.send(data);
        }
        
        // 1. Check when username field changes
        if (usernameInput) {
            usernameInput.addEventListener('blur', function() {
                check2FAStatus(this.value.trim());
            });
            
            usernameInput.addEventListener('input', function() {
                // Debounce the input check
                clearTimeout(window.moesecInputTimeout);
                window.moesecInputTimeout = setTimeout(function() {
                    check2FAStatus(usernameInput.value.trim());
                }, 500);
            });
        }
        
        // 2. Check when password field is focused
        if (passwordInput) {
            passwordInput.addEventListener('focus', function() {
                if (usernameInput && usernameInput.value.trim()) {
                    check2FAStatus(usernameInput.value.trim());
                }
            });
        }
        
        // 3. Check on page load if username is pre-filled
        if (usernameInput && usernameInput.value) {
            setTimeout(function() {
                check2FAStatus(usernameInput.value);
            }, 1000);
        }
        
        // 4. Auto-format 2FA code input
        if (codeInput) {
            codeInput.addEventListener('input', function() {
                var value = this.value.replace(/[^0-9]/g, '');
                if (value.length > 6) {
                    value = value.substring(0, 6);
                }
                this.value = value;
                
                // Visual feedback
                if (value.length === 6) {
                    this.style.borderColor = '#00a32a';
                    this.style.backgroundColor = '#f0fff0';
                } else {
                    this.style.borderColor = '#0073aa';
                    this.style.backgroundColor = 'white';
                }
            });
        }
        
        // 5. Check if we have any 2FA error messages
        var errorDiv = document.querySelector('.login #login_error');
        if (errorDiv) {
            var errorText = errorDiv.textContent || errorDiv.innerText;
            if (errorText.includes('Verification Code') || errorText.includes('2FA') || errorText.includes('authenticator')) {
                if (usernameInput && usernameInput.value) {
                    show2FAFields('email');
                }
            }
        }
        
    });
    </script>
    
    <style>
    #two_factor_code {
        transition: all 0.3s ease;
        border: 2px solid #0073aa !important;
    }
    
    #two_factor_code:focus {
        border-color: #00a0d2 !important;
        box-shadow: 0 0 0 1px #00a0d2 !important;
        outline: none !important;
    }
    
    #moesec-2fa-container {
        transition: all 0.3s ease;
    }
    
    /* Shake animation for errors */
    @keyframes moesec-shake {
        0%, 100% { transform: translateX(0); }
        10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
        20%, 40%, 60%, 80% { transform: translateX(5px); }
    }
    
    .moesec-error {
        animation: moesec-shake 0.5s ease-in-out;
        border-color: #dc3232 !important;
        background-color: #ffeaea !important;
    }
    </style>
    <?php
}

// AJAX handler for 2FA status check
add_action('wp_ajax_nopriv_moesec_check_2fa_status', 'moesec_ajax_check_2fa_status');
add_action('wp_ajax_moesec_check_2fa_status', 'moesec_ajax_check_2fa_status');
function moesec_ajax_check_2fa_status() {
    check_ajax_referer('moesec_2fa_nonce', 'nonce');
    
    // Check if 2FA is globally disabled first
    if (!get_option('moesec_enable_2fa', false)) {
        wp_send_json_success(array('enabled' => false));
    }
    
    $username = sanitize_user($_POST['username']);
    $user = get_user_by('login', $username);
    
    if (!$user) {
        $user = get_user_by('email', $username);
    }
    
    if ($user) {
        $is_forced = moesec_is_2fa_forced_for_user($user->ID);
        $is_enabled = get_user_meta($user->ID, 'moesec_2fa_enabled', true);
        
        if ($is_forced || $is_enabled) {
            $method = get_user_meta($user->ID, 'moesec_2fa_method', true) ?: 'email';
            wp_send_json_success(array('enabled' => true, 'method' => $method, 'forced' => $is_forced));
        }
    }
    
    wp_send_json_success(array('enabled' => false));
}

add_action('wp_ajax_nopriv_moesec_send_email_code', 'moesec_ajax_send_email_code');
add_action('wp_ajax_moesec_send_email_code', 'moesec_ajax_send_email_code');
function moesec_ajax_send_email_code() {
    check_ajax_referer('moesec_2fa_nonce', 'nonce');
    
    // Check if 2FA is globally disabled first
    if (!get_option('moesec_enable_2fa', false)) {
        wp_send_json_success(array('sent' => false));
    }
    
    $username = sanitize_user($_POST['username']);
    $user = get_user_by('login', $username);
    
    if (!$user) {
        $user = get_user_by('email', $username);
    }
    
    if ($user) {
        $is_forced = moesec_is_2fa_forced_for_user($user->ID);
        $is_enabled = get_user_meta($user->ID, 'moesec_2fa_enabled', true);
        
        if ($is_forced || $is_enabled) {
            $method = get_user_meta($user->ID, 'moesec_2fa_method', true) ?: 'email';
            if ($method === 'email') {
                $result = moesec_send_email_code($user);
                wp_send_json_success(array('sent' => true));
            }
        }
    }
    
    wp_send_json_success(array('sent' => false));
}

// ============================================================================
// AUTHENTICATION 
// ============================================================================

add_filter('authenticate', 'moesec_2fa_authenticate', 30, 5);
function moesec_2fa_authenticate($user, $username, $password) {
    // If authentication already failed, pass through
    if (is_wp_error($user)) {
        return $user;
    }
    
    if (!is_a($user, 'WP_User')) {
        return $user;
    }
    
    if (!get_option('moesec_enable_2fa', false)) {
        return $user;
    }
    
    $is_forced = moesec_is_2fa_forced_for_user($user->ID);
    $is_enabled = get_user_meta($user->ID, 'moesec_2fa_enabled', true);
    
    if (!$is_forced && !$is_enabled) {
        return $user;
    }
    
    $method = get_user_meta($user->ID, 'moesec_2fa_method', true) ?: 'email';
    $code = isset($_POST['two_factor_code']) ? trim($_POST['two_factor_code']) : '';
    
    if (empty($code)) {
        if ($method === 'email') {
            $result = moesec_send_email_code($user);
            return $result;
        } else {
            return new WP_Error(
                '2fa_required', 
                '<strong>Two-Factor Authentication Required</strong><br>Please enter the code from your authenticator app.'
            );
        }
    }
    
    $code = preg_replace('/[^0-9]/', '', $code);
    if (strlen($code) !== 6) {
        return new WP_Error(
            '2fa_invalid', 
            '<strong>Error:</strong> Verification code must be exactly 6 digits.'
        );
    }
    
    if ($method === 'google_auth') {
        $secret = get_user_meta($user->ID, 'moesec_2fa_secret', true);
        if (moesec_totp_verify($secret, $code)) {
            // Clear email sent flag if it exists
            delete_transient("moesec_recent_email_{$user->ID}");
            return $user;
        } else {
            return new WP_Error('2fa_invalid', '<strong>Error:</strong> Invalid verification code.');
        }
    } elseif ($method === 'email') {
        $stored_code = get_user_meta($user->ID, '_moesec_email_code', true);
        $stored_time = get_user_meta($user->ID, '_moesec_email_time', true);
        
        if (empty($stored_code) || empty($stored_time)) {
            return new WP_Error('2fa_error', '<strong>Error:</strong> No verification code found. Please try again.');
        }
        
        // Check if code expired (15 minutes)
        if ((time() - $stored_time) > 900) {
            delete_user_meta($user->ID, '_moesec_email_code');
            delete_user_meta($user->ID, '_moesec_email_time');
            delete_transient("moesec_recent_email_{$user->ID}");
            return new WP_Error('2fa_expired', '<strong>Error:</strong> Verification code expired. Please try again.');
        }
        
        if ($code === $stored_code) {
            // Clear the used code AND the email sent flag
            delete_user_meta($user->ID, '_moesec_email_code');
            delete_user_meta($user->ID, '_moesec_email_time');
            delete_transient("moesec_recent_email_{$user->ID}");
            return $user;
        } else {
            return new WP_Error('2fa_invalid', '<strong>Error:</strong> Invalid verification code.');
        }
    }
    
    return $user;
}

// ============================================================================
// ADMIN SETTINGS - WITH GLOBAL DISABLE
// ============================================================================

add_action('admin_menu', 'moesec_2fa_admin_menu');
function moesec_2fa_admin_menu() {
    add_options_page(
        'MoeSec 2FA Settings',
        'MoeSec 2FA',
        'manage_options',
        'moesec-2fa',
        'moesec_2fa_settings_page'
    );
}

function moesec_2fa_settings_page() {
    if (!current_user_can('manage_options')) {
        return;
    }
    
    // Handle form submission
    if (isset($_POST['moesec_2fa_settings_nonce']) && wp_verify_nonce($_POST['moesec_2fa_settings_nonce'], 'moesec_2fa_settings')) {
        $old_enabled = get_option('moesec_enable_2fa', false);
        $new_enabled = isset($_POST['moesec_enable_2fa']);
        
        update_option('moesec_enable_2fa', $new_enabled);
        
        $force_all = isset($_POST['moesec_force_2fa_all_users']) ? 1 : 0;
        update_option('moesec_force_2fa_all_users', $force_all);
        
        $force_roles = isset($_POST['moesec_force_2fa_roles']) ? array_map('sanitize_text_field', $_POST['moesec_force_2fa_roles']) : array();
        update_option('moesec_force_2fa_roles', $force_roles);
        
        $restrict_roles = isset($_POST['moesec_restrict_2fa_disable_roles']) ? array_map('sanitize_text_field', $_POST['moesec_restrict_2fa_disable_roles']) : array();
        update_option('moesec_restrict_2fa_disable_roles', $restrict_roles);
        
        $allowed_methods = isset($_POST['moesec_allowed_2fa_methods']) ? array_map('sanitize_text_field', $_POST['moesec_allowed_2fa_methods']) : array('email', 'google_auth');
        update_option('moesec_allowed_2fa_methods', $allowed_methods);
        
        //If disabling globally, deactivate all user 2FA settings
        if ($old_enabled && !$new_enabled) {
            $result = moesec_deactivate_all_users_2fa();
            $message = '2FA has been globally disabled and all user 2FA settings have been cleared.';
        } elseif (!$old_enabled && $new_enabled) {
            $message = '2FA has been globally enabled.';
        } else {
            $message = 'Settings saved.';
        }
        
        echo '<div class="notice notice-success"><p>' . esc_html($message) . '</p></div>';
    }
    
    $enabled = get_option('moesec_enable_2fa', false);
    $force_all = get_option('moesec_force_2fa_all_users', false);
    $force_roles = get_option('moesec_force_2fa_roles', array());
    $restrict_roles = get_option('moesec_restrict_2fa_disable_roles', array());
    $allowed_methods = get_option('moesec_allowed_2fa_methods', array('email', 'google_auth'));
    
    // Get all WordPress roles
    global $wp_roles;
    $roles = $wp_roles->get_names();
    
    ?>
    <div class="wrap">
        <h1>🔐 MoeSec Two-Factor Authentication</h1>
        
        <div style="background: #fff; border: 1px solid #ccd0d4; border-radius: 4px; padding: 20px; margin-top: 20px;">
            <form method="post">
                <?php wp_nonce_field('moesec_2fa_settings', 'moesec_2fa_settings_nonce'); ?>
                
                <table class="form-table">
                    <tr>
                        <th scope="row">
                            <label for="moesec_enable_2fa">Enable Two-Factor Authentication</label>
                        </th>
                        <td>
                            <input type="checkbox" name="moesec_enable_2fa" id="moesec_enable_2fa" value="1" <?php checked($enabled, true); ?>>
                            <label for="moesec_enable_2fa">Enable two-factor authentication system-wide</label>
                            <p class="description">
                                When enabled, users can configure 2FA in their profile. When disabled, all 2FA requirements are bypassed.
                            </p>
                        </td>
                    </tr>
                </table>
                
                <!-- Add role-based 2FA enforcement settings -->
                <?php if ($enabled): ?>
                <hr style="margin: 30px 0;">
                <h3>Role-Based 2FA Enforcement</h3>
                
                <table class="form-table">
                    <tr>
                        <th scope="row">
                            <label for="moesec_force_2fa_all_users">Force 2FA for All Users</label>
                        </th>
                        <td>
                            <input type="checkbox" name="moesec_force_2fa_all_users" id="moesec_force_2fa_all_users" value="1" <?php checked($force_all, true); ?>>
                            <label for="moesec_force_2fa_all_users">Require 2FA for all users</label>
                            <p class="description">
                                When enabled, all users must use 2FA and cannot disable it.
                            </p>
                        </td>
                    </tr>
                    
                    <tr>
                        <th scope="row">
                            <label>Force 2FA for Specific Roles</label>
                        </th>
                        <td>
                            <fieldset>
                                <?php foreach ($roles as $role_name => $role_display): ?>
                                    <label style="display: block; margin-bottom: 8px;">
                                        <input type="checkbox" name="moesec_force_2fa_roles[]" value="<?php echo esc_attr($role_name); ?>" <?php checked(in_array($role_name, $force_roles)); ?>>
                                        <?php echo esc_html($role_display); ?>
                                    </label>
                                <?php endforeach; ?>
                            </fieldset>
                            <p class="description">
                                Select roles that must use 2FA. Users in these roles cannot disable 2FA.
                            </p>
                        </td>
                    </tr>
                    
                    <tr>
                        <th scope="row">
                            <label>Restrict 2FA Disable for Roles</label>
                        </th>
                        <td>
                            <fieldset>
                                <?php foreach ($roles as $role_name => $role_display): ?>
                                    <label style="display: block; margin-bottom: 8px;">
                                        <input type="checkbox" name="moesec_restrict_2fa_disable_roles[]" value="<?php echo esc_attr($role_name); ?>" <?php checked(in_array($role_name, $restrict_roles)); ?>>
                                        <?php echo esc_html($role_display); ?>
                                    </label>
                                <?php endforeach; ?>
                            </fieldset>
                            <p class="description">
                                Select roles that cannot disable 2FA once enabled (even if not forced).
                            </p>
                        </td>
                    </tr>
                    
                    <tr>
                        <th scope="row">
                            <label>Allowed 2FA Methods</label>
                        </th>
                        <td>
                            <fieldset>
                                <label style="display: block; margin-bottom: 8px;">
                                    <input type="checkbox" name="moesec_allowed_2fa_methods[]" value="email" <?php checked(in_array('email', $allowed_methods)); ?>>
                                    📧 Email Code
                                </label>
                                <label style="display: block; margin-bottom: 8px;">
                                    <input type="checkbox" name="moesec_allowed_2fa_methods[]" value="google_auth" <?php checked(in_array('google_auth', $allowed_methods)); ?>>
                                    📱 Google Authenticator
                                </label>
                            </fieldset>
                            <p class="description">
                                Select which 2FA methods users can use. At least one method must be enabled.
                            </p>
                        </td>
                    </tr>
                </table>
                <?php endif; ?>
                
                <?php submit_button('Save Settings'); ?>
            </form>
        </div>
        
        <div style="margin-top: 30px; padding: 20px; background: #f0f7ff; border-radius: 4px;">
            <h3>📊 Statistics</h3>
            <?php
            $users_with_2fa = get_users(array(
                'meta_key' => 'moesec_2fa_enabled',
                'meta_value' => '1',
                'count_total' => true
            ));
            
            $total_users = count(get_users());
            ?>
            <p><strong>Users with 2FA enabled:</strong> <?php echo is_array($users_with_2fa) ? count($users_with_2fa) : $users_with_2fa; ?> out of <?php echo $total_users; ?></p>
            
            <?php if ($enabled): ?>
            <div style="margin-top: 15px;">
                <h4>⚠️ Global Disable Warning</h4>
                <p style="color: #d63638;">
                    <strong>Note:</strong> If you disable 2FA globally, all user-specific 2FA settings will be automatically cleared and users will be able to login without 2FA.
                </p>
            </div>
            <?php endif; ?>
        </div>
        
        <div style="margin-top: 20px; font-size: 12px; color: #666;">
            <p><strong>Powered by MoeSec.com Website Security</strong></p>
        </div>
    </div>
    <?php
}

// ============================================================================
// ACTIVATION/DEACTIVATION HOOKS
// ============================================================================

register_activation_hook(__FILE__, 'moesec_2fa_activate');
function moesec_2fa_activate() {
    add_option('moesec_enable_2fa', false);
    add_option('moesec_force_2fa_all_users', false);
    add_option('moesec_force_2fa_roles', array());
    add_option('moesec_restrict_2fa_disable_roles', array());
    add_option('moesec_allowed_2fa_methods', array('email', 'google_auth'));
}

register_deactivation_hook(__FILE__, 'moesec_2fa_deactivate');
function moesec_2fa_deactivate() {
    // When deactivating, clear all user 2FA settings to prevent conflicts
    moesec_deactivate_all_users_2fa();
}


add_action('send_headers', 'moesec_security_headers');
function moesec_security_headers() {
    if (!headers_sent()) {
        header('X-Content-Type-Options: nosniff');
        header('X-Frame-Options: SAMEORIGIN');
        header('X-XSS-Protection: 1; mode=block');
        header('Referrer-Policy: strict-origin-when-cross-origin');
    }
}
?>
