<?php
/**
 * Name: Magic Login
 * Description: Enable passwordless login via secure email links or 6-digit codes with QR code support. Auto-login links in outgoing emails via {{MAGIC_LINK}} placeholder.
 * Category: Security
 * Icon: -
 * Version: 2.0
 * Database: yes
 * UseCases: [
 *   {
 *     "title": "Passwordless Login",
 *     "description": "Allow users to sign in without remembering passwords - just enter email and click the link or scan QR code."
 *   },
 *   {
 *     "title": "Auto-Login Emails",
 *     "description": "Use {{MAGIC_LINK}} placeholder in any outgoing email to include a one-click login link for the recipient."
 *   },
 *   {
 *     "title": "Code Login Option",
 *     "description": "Users can choose to receive a 6-digit code instead of a link - ideal for mobile users."
 *   },
 *   {
 *     "title": "QR Code Login",
 *     "description": "Include scannable QR codes in login emails for quick mobile access."
 *   }
 * ]
 * Added: 2025-01-01
 * Tags: login, passwordless, magic link, email, authentication, auth, security, otp, one-time, verification, auto login, qr code
 * WhereToFind: {
 *   "location": "Login Page",
 *   "url": "wp-login.php",
 *   "instructions": "Magic login option appears on the login form. Use [magic_login] shortcode for custom forms.",
 *   "newTab": false
 * }
 */

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

class SwitchboardMagicLogin {

    private $table_name;
    private $default_expiry = 15; // minutes
    private $code_length = 6; // For code login
    private $encryption_key_option = 'switchboard_magic_login_encryption_key';

    /**
     * Encrypt sensitive data using AES-256-GCM
     *
     * @param string $data The data to encrypt
     * @return string|false Encrypted data (base64 encoded) or false on failure
     */
    private function encrypt_credential($data) {
        if (empty($data)) {
            return '';
        }

        $key = $this->get_encryption_key();
        if (!$key) {
            return false;
        }

        // Use AES-256-GCM for authenticated encryption
        $cipher = 'aes-256-gcm';
        $iv_length = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($iv_length);
        $tag = '';

        $encrypted = openssl_encrypt($data, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag, '', 16);
        if ($encrypted === false) {
            return false;
        }

        // Combine IV + tag + encrypted data and base64 encode
        return base64_encode($iv . $tag . $encrypted);
    }

    /**
     * Decrypt sensitive data
     *
     * @param string $encrypted_data The encrypted data (base64 encoded)
     * @return string|false Decrypted data or false on failure
     */
    private function decrypt_credential($encrypted_data) {
        if (empty($encrypted_data)) {
            return '';
        }

        // Check if data is encrypted (base64 and proper format)
        $decoded = base64_decode($encrypted_data, true);
        if ($decoded === false) {
            // Not encrypted, return as-is (for backwards compatibility)
            return $encrypted_data;
        }

        $key = $this->get_encryption_key();
        if (!$key) {
            return false;
        }

        $cipher = 'aes-256-gcm';
        $iv_length = openssl_cipher_iv_length($cipher);
        $tag_length = 16;

        // Check minimum length
        if (strlen($decoded) < $iv_length + $tag_length) {
            // Not encrypted properly, return as-is (backwards compatibility)
            return $encrypted_data;
        }

        // Extract IV, tag, and encrypted data
        $iv = substr($decoded, 0, $iv_length);
        $tag = substr($decoded, $iv_length, $tag_length);
        $encrypted = substr($decoded, $iv_length + $tag_length);

        $decrypted = openssl_decrypt($encrypted, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag);
        if ($decrypted === false) {
            // Decryption failed, might be plain text (backwards compatibility)
            return $encrypted_data;
        }

        return $decrypted;
    }

    /**
     * Get or generate encryption key
     *
     * @return string The encryption key
     */
    private function get_encryption_key() {
        // First, try to use LOGGED_IN_KEY if available (from wp-config.php)
        if (defined('LOGGED_IN_KEY') && strlen(LOGGED_IN_KEY) >= 32) {
            return hash('sha256', LOGGED_IN_KEY . 'switchboard_magic_login', true);
        }

        // Fallback: Generate and store a key
        $stored_key = get_option($this->encryption_key_option);
        if ($stored_key) {
            return base64_decode($stored_key);
        }

        // Generate new key
        $new_key = openssl_random_pseudo_bytes(32);
        update_option($this->encryption_key_option, base64_encode($new_key), false);
        return $new_key;
    }

    /**
     * Check if a credential value is encrypted
     *
     * @param string $value The value to check
     * @return bool True if encrypted
     */
    private function is_encrypted($value) {
        if (empty($value)) {
            return false;
        }
        $decoded = base64_decode($value, true);
        if ($decoded === false) {
            return false;
        }
        // Check if it looks like our encrypted format (IV + tag + data)
        $cipher = 'aes-256-gcm';
        $iv_length = openssl_cipher_iv_length($cipher);
        return strlen($decoded) > $iv_length + 16;
    }

    public function __construct() {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'switchboard_magic_links';

        // Create table on admin init and also on AJAX/login if needed
        add_action('admin_init', [$this, 'maybe_create_table']);
        add_action('login_init', [$this, 'maybe_create_table']);
        add_action('wp_ajax_nopriv_switchboard_request_magic_link', [$this, 'ensure_table_exists'], 1);
        add_action('wp_ajax_switchboard_request_magic_link', [$this, 'ensure_table_exists'], 1);

        // Add magic link option to login form
        add_action('login_form', [$this, 'render_login_form_option']);
        add_action('login_footer', [$this, 'render_login_scripts']);

        // Handle magic link form
        add_action('login_form_switchboard_magic_link', [$this, 'handle_magic_link_request']);
        add_action('login_form_switchboard_magic_verify', [$this, 'handle_magic_link_verify']);
        add_action('login_form_switchboard_magic_code', [$this, 'handle_code_login_page']);
        add_action('login_form_switchboard_magic_register', [$this, 'handle_registration_verify']);

        // AJAX handlers
        add_action('wp_ajax_nopriv_switchboard_request_magic_link', [$this, 'ajax_request_magic_link']);
        add_action('wp_ajax_switchboard_request_magic_link', [$this, 'ajax_request_magic_link']);
        add_action('wp_ajax_nopriv_switchboard_verify_magic_code', [$this, 'ajax_verify_magic_code']);
        add_action('wp_ajax_switchboard_verify_magic_code', [$this, 'ajax_verify_magic_code']);
        add_action('wp_ajax_switchboard_send_test_magic_email', [$this, 'ajax_send_test_magic_email']);

        // Shortcode
        add_shortcode('magic_login', [$this, 'render_shortcode']);

        // User list column
        add_filter('manage_users_columns', [$this, 'add_user_column']);
        add_filter('manage_users_custom_column', [$this, 'render_user_column'], 10, 3);

        // User profile section
        add_action('show_user_profile', [$this, 'render_profile_section']);
        add_action('edit_user_profile', [$this, 'render_profile_section']);
        add_action('personal_options_update', [$this, 'save_profile_section']);
        add_action('edit_user_profile_update', [$this, 'save_profile_section']);

        // Cleanup cron
        add_action('switchboard_magic_links_cleanup', [$this, 'cleanup_expired']);

        // Auto-login {{MAGIC_LINK}} placeholder in outgoing emails
        add_filter('wp_mail', [$this, 'process_magic_link_placeholder'], 10, 1);

        // Register Gutenberg block
        add_action('init', [$this, 'register_block'], 11);
        add_action('enqueue_block_editor_assets', [$this, 'enqueue_block_editor_assets']);

        // Module settings save filter (for encryption)
        add_filter('switchboard_before_save_settings', [$this, 'encrypt_settings_before_save'], 10, 2);
    }

    /**
     * Create database table
     */
    public function maybe_create_table() {
        global $wpdb;
        if ($wpdb->get_var("SHOW TABLES LIKE '{$this->table_name}'") != $this->table_name) {
            $this->create_table();
        } else {
            // Table exists - check if login_code column needs to be added (upgrade from older version)
            $this->maybe_upgrade_table();
        }
    }

    /**
     * Upgrade table schema if needed
     */
    private function maybe_upgrade_table() {
        global $wpdb;
        // Add login_code column if it doesn't exist (for upgrades from older versions)
        $row = $wpdb->get_results("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '{$this->table_name}' AND COLUMN_NAME = 'login_code'");
        if (empty($row)) {
            $wpdb->query("ALTER TABLE {$this->table_name} ADD login_code varchar(64) DEFAULT NULL AFTER token_hash");
            // Add index separately to avoid duplicate key error if it exists
            $wpdb->query("ALTER TABLE {$this->table_name} ADD KEY login_code (login_code)");
        }
    }

    /**
     * Ensure table exists (for AJAX calls)
     */
    public function ensure_table_exists() {
        $this->maybe_create_table();
    }

    private function create_table() {
        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE IF NOT EXISTS {$this->table_name} (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            user_id bigint(20) NOT NULL,
            token_hash varchar(64) NOT NULL,
            login_code varchar(64) DEFAULT NULL,
            expires_at datetime NOT NULL,
            created_at datetime NOT NULL,
            used_at datetime DEFAULT NULL,
            ip_address varchar(45) DEFAULT NULL,
            user_agent varchar(255) DEFAULT NULL,
            PRIMARY KEY (id),
            KEY user_id (user_id),
            KEY token_hash (token_hash),
            KEY login_code (login_code),
            KEY expires_at (expires_at)
        ) $charset_collate;";

        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql);

        // Add login_code column if it doesn't exist (for upgrades)
        $row = $wpdb->get_results("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '{$this->table_name}' AND COLUMN_NAME = 'login_code'");
        if (empty($row)) {
            $wpdb->query("ALTER TABLE {$this->table_name} ADD login_code varchar(64) DEFAULT NULL AFTER token_hash, ADD KEY login_code (login_code)");
        }
    }

    /**
     * Add column to users list
     */
    public function add_user_column($columns) {
        $columns['magic_login'] = __('Magic Login', 'wpswitchboard');
        return $columns;
    }

    /**
     * Render user column content
     */
    public function render_user_column($value, $column_name, $user_id) {
        if ($column_name !== 'magic_login') {
            return $value;
        }

        global $wpdb;

        // Get magic login stats for this user
        $total_logins = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$this->table_name} WHERE user_id = %d AND used_at IS NOT NULL",
            $user_id
        ));

        $last_login = $wpdb->get_var($wpdb->prepare(
            "SELECT used_at FROM {$this->table_name} WHERE user_id = %d AND used_at IS NOT NULL ORDER BY used_at DESC LIMIT 1",
            $user_id
        ));

        if ($total_logins > 0) {
            $last_login_timestamp = $last_login ? strtotime($last_login) : false;
            $time_ago = $last_login_timestamp ? human_time_diff($last_login_timestamp) : __('Unknown', 'wpswitchboard');
            return sprintf(
                '<span style="color: #16a34a;" title="%s">%s</span><br><span style="color: #64748b; font-size: 12px;">%s ago</span>',
                esc_attr(sprintf(__('%d magic logins', 'wpswitchboard'), $total_logins)),
                sprintf(_n('%d login', '%d logins', $total_logins, 'wpswitchboard'), $total_logins),
                esc_html($time_ago)
            );
        }

        return '<span style="color: #9ca3af;">—</span>';
    }

    /**
     * Render login activity on user profile page
     */
    public function render_profile_section($user) {
        global $wpdb;

        $is_own_profile = $user->ID === get_current_user_id();
        if (!$is_own_profile && !current_user_can('manage_options')) {
            return;
        }

        // Check if SMS is available
        $settings = get_option('switchboard_magic-login_settings', []);
        $sms_available = !empty($settings['twilio_account_sid']) && !empty($settings['twilio_auth_token']) && !empty($settings['twilio_phone_number']);
        $magic_phone = get_user_meta($user->ID, 'switchboard_magic_login_phone', true);

        // Get recent magic links for this user (limit to 5 for profile)
        $recent_links = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$this->table_name} WHERE user_id = %d ORDER BY created_at DESC LIMIT 5",
            $user->ID
        ));
        ?>
        <h2><?php _e('Magic Login', 'wpswitchboard'); ?> <span class="switchboard-badge">Switchboard</span></h2>
        <table class="form-table" role="presentation">
            <?php if ($sms_available): ?>
            <tr>
                <th scope="row"><label for="switchboard_magic_login_phone"><?php _e('Phone Number', 'wpswitchboard'); ?></label></th>
                <td>
                    <input type="tel" name="switchboard_magic_login_phone" id="switchboard_magic_login_phone" value="<?php echo esc_attr($magic_phone); ?>" class="regular-text" placeholder="+1234567890">
                    <p class="description"><?php _e('Required for SMS login codes. Include country code (e.g., +1 for US).', 'wpswitchboard'); ?></p>
                </td>
            </tr>
            <?php endif; ?>
            <?php if (!empty($recent_links)): ?>
            <tr>
                <th scope="row"><?php _e('Recent Logins', 'wpswitchboard'); ?></th>
                <td>
                    <div style="max-width: 500px;">
                        <?php foreach ($recent_links as $index => $link):
                            $is_used = !empty($link->used_at);
                            $expires_timestamp = $link->expires_at ? strtotime($link->expires_at . ' UTC') : 0;
                            $is_expired = $expires_timestamp && $expires_timestamp < time();
                            $expires_in = $expires_timestamp ? $expires_timestamp - time() : 0;

                            if ($is_used) {
                                $icon = 'Used:'; $status = __('Used', 'wpswitchboard'); $color = '#16a34a';
                                $used_timestamp = $link->used_at ? strtotime($link->used_at) : false;
                                $time = $used_timestamp ? sprintf(__('%s ago', 'wpswitchboard'), human_time_diff($used_timestamp)) : '—';
                            } elseif ($is_expired) {
                                $icon = 'Expired:'; $status = __('Expired', 'wpswitchboard'); $color = '#9ca3af';
                                $time = $expires_timestamp ? sprintf(__('%s ago', 'wpswitchboard'), human_time_diff($expires_timestamp)) : '—';
                            } else {
                                $icon = 'Pending:'; $status = __('Pending', 'wpswitchboard'); $color = '#d97706';
                                $time = $expires_in > 0 ? sprintf(__('expires in %d min', 'wpswitchboard'), ceil($expires_in / 60)) : '—';
                            }
                        ?>
                            <div style="display: flex; align-items: center; gap: 8px; padding: 6px 0; <?php echo $index < count($recent_links) - 1 ? 'border-bottom: 1px solid #f0f0f1;' : ''; ?>">
                                <span style="color: <?php echo $color; ?>;"><?php echo $icon; ?></span>
                                <span style="color: <?php echo $color; ?>; font-weight: 500;"><?php echo $status; ?></span>
                                <span style="color: #646970;">— <?php echo $time; ?></span>
                                <span style="color: #a7aaad; font-size: 12px; margin-left: auto;"><?php echo esc_html($link->ip_address ?: ''); ?></span>
                            </div>
                        <?php endforeach; ?>
                    </div>
                </td>
            </tr>
            <?php endif; ?>
        </table>
        <?php
    }

    /**
     * Save user profile settings
     */
    public function save_profile_section($user_id) {
        if (!current_user_can('edit_user', $user_id)) {
            return;
        }

        if (isset($_POST['switchboard_magic_login_phone'])) {
            $phone = sanitize_text_field($_POST['switchboard_magic_login_phone']);
            if (!empty($phone)) {
                // Normalize phone number
                $phone = $this->normalize_phone_number($phone);
                update_user_meta($user_id, 'switchboard_magic_login_phone', $phone);
            } else {
                delete_user_meta($user_id, 'switchboard_magic_login_phone');
            }
        }
    }

    /**
     * Adjust hex color brightness
     */
    private function adjust_brightness($hex, $percent) {
        $hex = ltrim($hex, '#');
        if (strlen($hex) === 3) {
            $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
        }

        $r = hexdec(substr($hex, 0, 2));
        $g = hexdec(substr($hex, 2, 2));
        $b = hexdec(substr($hex, 4, 2));

        $r = max(0, min(255, $r + ($r * $percent / 100)));
        $g = max(0, min(255, $g + ($g * $percent / 100)));
        $b = max(0, min(255, $b + ($b * $percent / 100)));

        return sprintf('#%02x%02x%02x', $r, $g, $b);
    }

    /**
     * Render shortcode for magic login form
     * Usage: [magic_login title="Sign In" button="Send Link" redirect="/dashboard"]
     */
    public function render_shortcode($atts) {
        // Get saved settings
        $settings = get_option('switchboard_magic-login_settings', []);

        // Get saved content defaults
        $default_title = isset($settings['sc_title']) ? $settings['sc_title'] : __('Sign in with email', 'wpswitchboard');
        $default_desc = isset($settings['sc_description']) ? $settings['sc_description'] : __("Enter your email and we'll send you a link to sign in instantly.", 'wpswitchboard');
        $default_button = isset($settings['sc_button_text']) ? $settings['sc_button_text'] : __('Send Login Link', 'wpswitchboard');
        $default_show_pwd = isset($settings['sc_show_password_link']) ? $settings['sc_show_password_link'] : 'yes';

        $atts = shortcode_atts([
            'title' => $default_title,
            'description' => $default_desc,
            'button' => $default_button,
            'redirect' => isset($settings['sc_redirect']) ? $settings['sc_redirect'] : '',
            'class' => '',
            'show_password_link' => $default_show_pwd,
            'mode' => 'auto', // 'login', 'register', or 'auto' (smart detection - default!)
        ], $atts, 'magic_login');

        // Check if registration is enabled for smart defaults
        $enable_registration = isset($settings['enable_registration']) ? $settings['enable_registration'] === 'yes' : false;

        // Adjust defaults based on mode
        if ($atts['mode'] === 'register') {
            // Explicit register mode
            if ($atts['title'] === $default_title) {
                $atts['title'] = __('Create an account', 'wpswitchboard');
            }
            if ($atts['description'] === $default_desc) {
                $atts['description'] = __("Enter your email and we'll send you a link to create your account.", 'wpswitchboard');
            }
            if ($atts['button'] === $default_button) {
                $atts['button'] = __('Send Registration Link', 'wpswitchboard');
            }
        } elseif ($atts['mode'] === 'auto' && $enable_registration) {
            // Auto mode with registration enabled - use inclusive messaging
            if ($atts['title'] === $default_title) {
                $atts['title'] = __('Continue with email', 'wpswitchboard');
            }
            if ($atts['description'] === $default_desc) {
                $atts['description'] = __("Enter your email to sign in or create an account.", 'wpswitchboard');
            }
            if ($atts['button'] === $default_button) {
                $atts['button'] = __('Continue', 'wpswitchboard');
            }
        }
        // For 'login' mode or 'auto' without registration, use the saved defaults

        // Don't show if already logged in
        if (is_user_logged_in()) {
            return '<p>' . __('You are already logged in.', 'wpswitchboard') . '</p>';
        }

        // Get style settings with defaults
        $style_bg = isset($settings['style_bg_color']) ? $settings['style_bg_color'] : '#ffffff';
        $style_border = isset($settings['style_border_color']) ? $settings['style_border_color'] : '#e2e8f0';
        $style_radius = isset($settings['style_border_radius']) ? intval($settings['style_border_radius']) : 12;
        $style_title_color = isset($settings['style_title_color']) ? $settings['style_title_color'] : '#1e293b';
        $style_desc_color = isset($settings['style_desc_color']) ? $settings['style_desc_color'] : '#64748b';
        $style_input_border = isset($settings['style_input_border_color']) ? $settings['style_input_border_color'] : '#d1d5db';
        $style_input_radius = isset($settings['style_input_border_radius']) ? intval($settings['style_input_border_radius']) : 8;
        $style_btn_bg = isset($settings['style_button_bg']) ? $settings['style_button_bg'] : '#3b82f6';
        $style_btn_text = isset($settings['style_button_text_color']) ? $settings['style_button_text_color'] : '#ffffff';
        $style_btn_radius = isset($settings['style_button_radius']) ? intval($settings['style_button_radius']) : 8;
        $custom_css = isset($settings['shortcode_css']) ? $settings['shortcode_css'] : '';

        // Calculate hover color (slightly darker)
        $btn_hover = $this->adjust_brightness($style_btn_bg, -15);

        $redirect_to = !empty($atts['redirect']) ? esc_url($atts['redirect']) : '';
        $form_id = 'magic-login-form-' . wp_rand(1000, 9999);

        ob_start();
        ?>
        <div class="switchboard-magic-login-form <?php echo esc_attr($atts['class']); ?>" id="<?php echo esc_attr($form_id); ?>-wrapper">
            <style>
                #<?php echo esc_attr($form_id); ?>-wrapper.switchboard-magic-login-form {
                    max-width: 400px;
                    margin: 0 auto;
                    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-form-container {
                    background: <?php echo esc_attr($style_bg); ?>;
                    border: 1px solid <?php echo esc_attr($style_border); ?>;
                    border-radius: <?php echo esc_attr($style_radius); ?>px;
                    padding: 32px;
                    text-align: center;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-title {
                    font-size: 24px;
                    font-weight: 600;
                    color: <?php echo esc_attr($style_title_color); ?>;
                    margin: 0 0 8px;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-desc {
                    color: <?php echo esc_attr($style_desc_color); ?>;
                    font-size: 14px;
                    margin: 0 0 24px;
                    line-height: 1.5;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-input {
                    width: 100%;
                    padding: 12px 16px;
                    border: 1px solid <?php echo esc_attr($style_input_border); ?>;
                    border-radius: <?php echo esc_attr($style_input_radius); ?>px;
                    font-size: 16px;
                    margin-bottom: 16px;
                    box-sizing: border-box;
                    transition: border-color 0.15s, box-shadow 0.15s;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-input:focus {
                    outline: none;
                    border-color: <?php echo esc_attr($style_btn_bg); ?>;
                    box-shadow: 0 0 0 3px <?php echo esc_attr($style_btn_bg); ?>1a;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-button {
                    width: 100%;
                    padding: 14px 24px;
                    background: <?php echo esc_attr($style_btn_bg); ?>;
                    color: <?php echo esc_attr($style_btn_text); ?>;
                    border: none;
                    border-radius: <?php echo esc_attr($style_btn_radius); ?>px;
                    font-size: 16px;
                    font-weight: 600;
                    cursor: pointer;
                    transition: background 0.15s, transform 0.15s;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-button:hover {
                    background: <?php echo esc_attr($btn_hover); ?>;
                    transform: translateY(-1px);
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-button:disabled {
                    background: #94a3b8;
                    cursor: not-allowed;
                    transform: none;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-success {
                    background: #f0fdf4;
                    border: 1px solid #bbf7d0;
                    border-radius: <?php echo esc_attr($style_radius); ?>px;
                    padding: 20px;
                    text-align: center;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-success h3 {
                    color: #16a34a;
                    margin: 0 0 8px;
                    font-size: 18px;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-success p {
                    color: #166534;
                    margin: 0;
                    font-size: 14px;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-error {
                    background: #fef2f2;
                    border: 1px solid #fecaca;
                    color: #dc2626;
                    padding: 12px;
                    border-radius: 8px;
                    margin-bottom: 16px;
                    font-size: 14px;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-password-link {
                    margin-top: 16px;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-password-link a {
                    color: <?php echo esc_attr($style_desc_color); ?>;
                    text-decoration: none;
                    font-size: 13px;
                }
                #<?php echo esc_attr($form_id); ?>-wrapper .sml-password-link a:hover {
                    text-decoration: underline;
                }
                <?php
                // Sanitize custom CSS to prevent XSS
                // Only allow CSS, strip any HTML tags that could escape the style block
                if (!empty($custom_css)) {
                    // Remove any closing style tags or opening script/html tags
                    $safe_css = preg_replace('/<\s*\/?\s*(style|script|html|body|head|meta|link|iframe|object|embed)[^>]*>/i', '', $custom_css);
                    // Remove javascript: protocol
                    $safe_css = preg_replace('/javascript\s*:/i', '', $safe_css);
                    // Remove expression() which is IE-specific XSS vector
                    $safe_css = preg_replace('/expression\s*\(/i', '', $safe_css);
                    // Remove url() with data: protocol (potential XSS vector)
                    $safe_css = preg_replace('/url\s*\(\s*["\']?\s*data:/i', 'url(blocked:', $safe_css);
                    echo $safe_css;
                }
                ?>
            </style>

            <div class="sml-form-container">
                <?php if (!empty($atts['title'])): ?>
                    <h3 class="sml-title"><?php echo esc_html($atts['title']); ?></h3>
                <?php endif; ?>
                <?php if (!empty($atts['description'])): ?>
                    <p class="sml-desc"><?php echo esc_html($atts['description']); ?></p>
                <?php endif; ?>

                <div class="sml-message" style="display: none;"></div>

                <form class="sml-form">
                    <?php wp_nonce_field('switchboard_magic_link', 'switchboard_magic_nonce'); ?>
                    <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>">
                    <input type="hidden" name="mode" value="<?php echo esc_attr($atts['mode']); ?>">

                    <input type="email" name="email" class="sml-input" placeholder="<?php esc_attr_e('Email address', 'wpswitchboard'); ?>" required>

                    <?php
                    // Hook for CAPTCHA integration (reCAPTCHA, Turnstile, etc.)
                    do_action('switchboard_magic_login_form_fields', $form_id);
                    ?>

                    <button type="submit" class="sml-button"><?php echo esc_html($atts['button']); ?></button>
                </form>

                <?php if ($atts['show_password_link'] === 'yes'): ?>
                    <div class="sml-password-link">
                        <a href="<?php echo esc_url(wp_login_url()); ?>"><?php _e('Use password instead', 'wpswitchboard'); ?> →</a>
                    </div>
                <?php endif; ?>
            </div>
        </div>

        <script>
        (function() {
            var wrapper = document.getElementById('<?php echo esc_js($form_id); ?>-wrapper');
            var form = wrapper.querySelector('.sml-form');
            var messageDiv = wrapper.querySelector('.sml-message');
            var formContainer = wrapper.querySelector('.sml-form-container');

            form.addEventListener('submit', function(e) {
                e.preventDefault();
                var btn = form.querySelector('button');
                var email = form.querySelector('input[name="email"]').value;
                var nonce = form.querySelector('input[name="switchboard_magic_nonce"]').value;
                var redirect = form.querySelector('input[name="redirect_to"]').value;
                var mode = form.querySelector('input[name="mode"]').value;

                btn.disabled = true;
                btn.textContent = '<?php echo esc_js(__('Sending...', 'wpswitchboard')); ?>';
                messageDiv.style.display = 'none';

                var xhr = new XMLHttpRequest();
                xhr.open('POST', '<?php echo admin_url('admin-ajax.php'); ?>');
                xhr.onload = function() {
                    btn.disabled = false;
                    btn.textContent = '<?php echo esc_js($atts['button']); ?>';

                    try {
                        var response = JSON.parse(xhr.responseText);
                        if (response.success) {
                            // Use personalized title/subtitle from server if available
                            var successTitle = response.data.title || '<?php echo esc_js(__('Check your email!', 'wpswitchboard')); ?>';
                            var successSubtitle = response.data.subtitle || '<?php echo esc_js(__("We've sent a link to your email address.", 'wpswitchboard')); ?>';
                            // Create elements safely to prevent XSS
                            var successDiv = document.createElement('div');
                            successDiv.className = 'sml-success';
                            var h3 = document.createElement('h3');
                            h3.textContent = successTitle;
                            var p = document.createElement('p');
                            p.textContent = successSubtitle;
                            successDiv.appendChild(h3);
                            successDiv.appendChild(p);
                            formContainer.innerHTML = '';
                            formContainer.appendChild(successDiv);
                        } else {
                            messageDiv.className = 'sml-message sml-error';
                            messageDiv.textContent = response.data.message || '<?php echo esc_js(__('An error occurred.', 'wpswitchboard')); ?>';
                            messageDiv.style.display = 'block';
                        }
                    } catch (err) {
                        messageDiv.className = 'sml-message sml-error';
                        messageDiv.textContent = '<?php echo esc_js(__('An error occurred.', 'wpswitchboard')); ?>';
                        messageDiv.style.display = 'block';
                    }
                };
                // Build form data including CAPTCHA fields
                var formData = new FormData(form);
                formData.append('action', 'switchboard_request_magic_link');
                formData.append('nonce', nonce);
                xhr.send(formData);
            });
        })();
        </script>
        <?php
        return ob_get_clean();
    }

    /**
     * Add magic link option to login form
     */
    public function render_login_form_option() {
        $settings = get_option('switchboard_magic-login_settings', []);
        $show_on_login = isset($settings['show_on_login']) ? $settings['show_on_login'] : 'yes';

        if ($show_on_login !== 'yes') {
            return;
        }
        ?>
        <div id="switchboard-magic-link-option" style="margin: 20px 0; text-align: center;">
            <div style="position: relative; margin: 20px 0;">
                <hr style="border: none; border-top: 1px solid #dcdcde; margin: 0;">
                <span style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #fff; padding: 0 12px; color: #787c82; font-size: 13px;">
                    <?php _e('or', 'wpswitchboard'); ?>
                </span>
            </div>
            <button type="button" id="switchboard-magic-link-btn" class="button button-large" style="width: 100%; max-width: 100%; height: 40px; font-size: 14px; box-sizing: border-box;">
                <?php _e('Email me a login link', 'wpswitchboard'); ?>
            </button>
        </div>
        <?php
    }

    /**
     * Render JavaScript for login form
     */
    public function render_login_scripts() {
        $settings = get_option('switchboard_magic-login_settings', []);
        $show_on_login = isset($settings['show_on_login']) ? $settings['show_on_login'] : 'yes';

        if ($show_on_login !== 'yes') {
            return;
        }

        // Check if SMS is enabled and configured
        $magic_settings = get_option('switchboard_magic-login_settings', []);
        $sms_enabled = isset($magic_settings['sms_enabled']) && $magic_settings['sms_enabled'] === 'yes';
        $twilio_configured = !empty($magic_settings['twilio_account_sid']) && !empty($magic_settings['twilio_auth_token']) && !empty($magic_settings['twilio_phone_number']);
        $show_sms_option = $sms_enabled && $twilio_configured;
        ?>
        <style>
            /* Magic login mode - hide password field */
            #loginform.magic-login-mode .user-pass-wrap,
            #loginform.magic-login-mode .forgetmenot {
                display: none !important;
            }
            /* SMS option styling */
            #switchboard-magic-sms-option {
                display: none;
                margin: 12px 0;
                padding: 12px;
                background: #f8fafc;
                border-radius: 6px;
            }
            #loginform.magic-login-mode #switchboard-magic-sms-option {
                display: block;
            }
            #switchboard-magic-sms-option label {
                display: flex;
                align-items: flex-start;
                gap: 8px;
                cursor: pointer;
                font-size: 14px;
            }
            #switchboard-magic-sms-option input[type="checkbox"] {
                margin-top: 2px;
            }
            #switchboard-magic-sms-option .sms-hint {
                font-size: 12px;
                color: #6b7280;
                margin-top: 4px;
                display: block;
            }
            /* Success message styling */
            .switchboard-magic-success {
                background: #f0fdf4;
                border: 1px solid #bbf7d0;
                border-radius: 4px;
                padding: 16px;
                margin-bottom: 16px;
                text-align: center;
            }
            .switchboard-magic-success h3 {
                color: #16a34a;
                margin: 0 0 8px;
                font-size: 16px;
            }
            .switchboard-magic-success p {
                color: #166534;
                margin: 0;
                font-size: 14px;
            }
            /* Error message styling */
            .switchboard-magic-error {
                background: #fef2f2;
                border: 1px solid #fecaca;
                border-radius: 4px;
                padding: 12px;
                margin-bottom: 16px;
                color: #dc2626;
                font-size: 14px;
            }
            /* Back to password link */
            #switchboard-back-to-password {
                display: none;
                text-align: center;
                margin-top: 16px;
            }
            #loginform.magic-login-mode ~ #nav #switchboard-back-to-password,
            #switchboard-back-to-password.visible {
                display: block;
            }
        </style>

        <!-- SMS option (injected into login form via JS) -->
        <div id="switchboard-magic-sms-template" style="display: none;">
            <?php if ($show_sms_option): ?>
            <div id="switchboard-magic-sms-option">
                <label>
                    <input type="checkbox" id="switchboard_magic_sms" name="switchboard_magic_sms" value="1">
                    <span>
                        <?php _e('Send code via SMS instead', 'wpswitchboard'); ?>
                        <span class="sms-hint"><?php _e('Requires phone number in your profile', 'wpswitchboard'); ?></span>
                    </span>
                </label>
            </div>
            <?php endif; ?>
        </div>

        <!-- Hidden nonce field template -->
        <div id="switchboard-magic-nonce-template" style="display: none;">
            <?php wp_nonce_field('switchboard_magic_link', 'switchboard_magic_nonce'); ?>
        </div>

        <!-- Message container (inserted into login form via JS) -->
        <div id="switchboard-magic-message-template" style="display: none;">
            <div id="switchboard-magic-message"></div>
        </div>

        <script>
        (function() {
            var magicBtn = document.getElementById('switchboard-magic-link-btn');
            var loginForm = document.getElementById('loginform');
            var magicOption = document.getElementById('switchboard-magic-link-option');

            if (!magicBtn || !loginForm) return;

            var isMagicMode = false;
            var submitBtn = loginForm.querySelector('#wp-submit');
            var originalBtnText = submitBtn ? submitBtn.value : 'Log In';
            var emailBtnText = '<?php echo esc_js(__('Send Login Link', 'wpswitchboard')); ?>';
            var smsBtnText = '<?php echo esc_js(__('Send Login Code', 'wpswitchboard')); ?>';

            // Get the SMS option template and nonce template
            var smsTemplate = document.getElementById('switchboard-magic-sms-template');
            var nonceTemplate = document.getElementById('switchboard-magic-nonce-template');
            var messageTemplate = document.getElementById('switchboard-magic-message-template');

            // Create back to password link
            var backLink = document.createElement('p');
            backLink.id = 'switchboard-back-to-password';
            backLink.innerHTML = '<a href="#">&larr; <?php echo esc_js(__('Back to password login', 'wpswitchboard')); ?></a>';

            // Insert message container at top of form
            var messageDiv = document.createElement('div');
            messageDiv.id = 'switchboard-magic-message';
            loginForm.insertBefore(messageDiv, loginForm.firstChild);

            // Insert SMS option after user-pass-wrap
            var userPassWrap = loginForm.querySelector('.user-pass-wrap');
            var smsOptionDiv = null;
            if (smsTemplate && smsTemplate.innerHTML.trim() && userPassWrap) {
                smsOptionDiv = document.createElement('div');
                smsOptionDiv.innerHTML = smsTemplate.innerHTML;
                userPassWrap.parentNode.insertBefore(smsOptionDiv.firstElementChild || smsOptionDiv, userPassWrap.nextSibling);
            }

            // Insert nonce field - append the input directly, not wrapped in div
            if (nonceTemplate) {
                var tempDiv = document.createElement('div');
                tempDiv.innerHTML = nonceTemplate.innerHTML;
                var inputs = tempDiv.querySelectorAll('input');
                inputs.forEach(function(input) {
                    loginForm.appendChild(input.cloneNode(true));
                });
            }

            // Insert back link after nav
            var nav = document.getElementById('nav');
            if (nav) {
                nav.parentNode.insertBefore(backLink, nav.nextSibling);
            }

            var smsCheckbox = document.getElementById('switchboard_magic_sms');
            var passwordField = document.getElementById('user_pass');

            // Toggle to Magic Login mode
            magicBtn.addEventListener('click', function(e) {
                e.preventDefault();
                isMagicMode = true;
                loginForm.classList.add('magic-login-mode');
                magicOption.style.display = 'none';
                backLink.style.display = 'block';
                submitBtn.value = (smsCheckbox && smsCheckbox.checked) ? smsBtnText : emailBtnText;
                messageDiv.innerHTML = '';
                // Remove required from password field so form can submit
                if (passwordField) {
                    passwordField.removeAttribute('required');
                }
            });

            // Toggle back to Password mode
            backLink.querySelector('a').addEventListener('click', function(e) {
                e.preventDefault();
                isMagicMode = false;
                loginForm.classList.remove('magic-login-mode');
                magicOption.style.display = 'block';
                backLink.style.display = 'none';
                submitBtn.value = originalBtnText;
                submitBtn.disabled = false;
                messageDiv.innerHTML = '';
                // Restore required on password field
                if (passwordField) {
                    passwordField.setAttribute('required', 'required');
                }
            });

            // SMS checkbox handling
            if (smsCheckbox) {
                smsCheckbox.addEventListener('change', function() {
                    if (isMagicMode) {
                        submitBtn.value = this.checked ? smsBtnText : emailBtnText;
                    }
                });
            }

            // Intercept form submission in magic mode
            loginForm.addEventListener('submit', function(e) {
                if (!isMagicMode) return; // Let normal login proceed

                e.preventDefault();

                var emailInput = loginForm.querySelector('#user_login');
                var email = emailInput ? emailInput.value : '';
                var isSms = smsCheckbox && smsCheckbox.checked;
                var currentBtnText = submitBtn.value;

                if (!email) {
                    messageDiv.innerHTML = '<div class="switchboard-magic-error"><?php echo esc_js(__('Please enter your email address.', 'wpswitchboard')); ?></div>';
                    return;
                }

                submitBtn.disabled = true;
                submitBtn.value = '<?php echo esc_js(__('Sending...', 'wpswitchboard')); ?>';
                messageDiv.innerHTML = '';

                // Build form data
                var formData = new FormData(loginForm);
                formData.append('action', 'switchboard_request_magic_link');
                formData.append('email', email);
                if (isSms) {
                    formData.set('delivery_method', 'sms');
                }

                // Get nonce
                var nonceField = loginForm.querySelector('[name="switchboard_magic_nonce"]');
                if (nonceField) {
                    formData.append('nonce', nonceField.value);
                }

                var xhr = new XMLHttpRequest();
                xhr.open('POST', '<?php echo admin_url('admin-ajax.php'); ?>');
                xhr.onload = function() {
                    submitBtn.disabled = false;
                    submitBtn.value = currentBtnText;

                    try {
                        var response = JSON.parse(xhr.responseText);
                        if (response.success) {
                            var successTitle = response.data.title || '<?php echo esc_js(__('Check your email!', 'wpswitchboard')); ?>';
                            var successSubtitle = response.data.subtitle || '<?php echo esc_js(__("We've sent a login link to your email address.", 'wpswitchboard')); ?>';

                            // Hide all form fields on success
                            var allFormElements = loginForm.querySelectorAll('p, label, input, .user-login-wrap, .user-pass-wrap, .submit, .forgetmenot, .cf-turnstile, .g-recaptcha, .switchboard-captcha, #switchboard-magic-sms-option');
                            allFormElements.forEach(function(el) { el.style.display = 'none'; });
                            if (backLink) backLink.style.display = 'none';
                            if (magicOption) magicOption.style.display = 'none';

                            messageDiv.innerHTML = '';
                            var successDiv = document.createElement('div');
                            successDiv.className = 'switchboard-magic-success';
                            successDiv.innerHTML = '<h3>' + successTitle + '</h3><p>' + successSubtitle + '</p>';
                            messageDiv.appendChild(successDiv);

                            var tryAgainLink = document.createElement('a');
                            tryAgainLink.href = '<?php echo esc_url(wp_login_url()); ?>';
                            tryAgainLink.style.cssText = 'display: block; text-align: center; margin-top: 16px; color: #2271b1;';
                            tryAgainLink.innerHTML = '&larr; <?php echo esc_js(__('Back to login', 'wpswitchboard')); ?>';
                            messageDiv.appendChild(tryAgainLink);
                        } else {
                            var errorMsg = (response.data && response.data.message) ? response.data.message : '<?php echo esc_js(__('An error occurred. Please try again.', 'wpswitchboard')); ?>';
                            messageDiv.innerHTML = '<div class="switchboard-magic-error">' + errorMsg + '</div>';
                        }
                    } catch (err) {
                        messageDiv.innerHTML = '<div class="switchboard-magic-error"><?php echo esc_js(__('An error occurred. Please try again.', 'wpswitchboard')); ?></div>';
                    }
                };
                xhr.onerror = function() {
                    submitBtn.disabled = false;
                    submitBtn.value = currentBtnText;
                    messageDiv.innerHTML = '<div class="switchboard-magic-error"><?php echo esc_js(__('Connection error. Please try again.', 'wpswitchboard')); ?></div>';
                };
                xhr.send(formData);
            });
        })();
        </script>
        <?php
    }

    /**
     * AJAX: Handle magic link request
     */
    public function ajax_request_magic_link() {
        // Log incoming request for debugging
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log('Switchboard Magic Login: Request received - email: ' . ($_POST['email'] ?? 'none') . ', delivery: ' . ($_POST['delivery_method'] ?? 'email'));
        }

        // Verify nonce
        if (!wp_verify_nonce($_POST['nonce'] ?? '', 'switchboard_magic_link')) {
            wp_send_json_error(['message' => __('Security check failed. Please refresh and try again.', 'wpswitchboard')]);
        }

        $email = sanitize_email($_POST['email'] ?? '');
        $redirect_to = isset($_POST['redirect_to']) ? esc_url_raw($_POST['redirect_to']) : '';
        $delivery_method = isset($_POST['delivery_method']) && $_POST['delivery_method'] === 'sms' ? 'sms' : 'email';

        if (!is_email($email)) {
            wp_send_json_error(['message' => __('Please enter a valid email address.', 'wpswitchboard')]);
        }

        // CAPTCHA validation filter (reCAPTCHA, Turnstile, etc.)
        $captcha_valid = apply_filters('switchboard_magic_login_validate', true, $email);
        if (is_wp_error($captcha_valid)) {
            wp_send_json_error(['message' => $captcha_valid->get_error_message()]);
        }
        if ($captcha_valid === false) {
            wp_send_json_error(['message' => __('CAPTCHA verification failed. Please try again.', 'wpswitchboard')]);
        }

        // Rate limiting by IP
        $ip = $this->get_client_ip();
        $rate_key = 'switchboard_magic_rate_' . md5($ip);
        $requests = get_transient($rate_key);

        /**
         * Filter the maximum number of login requests allowed per IP address.
         *
         * @param int $max_requests Maximum requests per IP (default 5).
         * @param string $ip The client IP address.
         */
        $max_ip_requests = apply_filters('switchboard_magic_login_max_ip_requests', 5, $ip);

        if ($requests && $requests >= $max_ip_requests) {
            /**
             * Filter the rate limit error message.
             *
             * @param string $message The error message.
             * @param string $ip The client IP address.
             */
            $rate_limit_message = apply_filters(
                'switchboard_magic_login_rate_limit_message',
                __('Too many requests. Please try again in a few minutes.', 'wpswitchboard'),
                $ip
            );
            wp_send_json_error(['message' => $rate_limit_message]);
        }

        // Rate limiting by email
        $email_rate_key = 'switchboard_magic_email_' . md5($email);
        $email_requests = get_transient($email_rate_key);

        /**
         * Filter the maximum number of login requests allowed per email address.
         *
         * @param int $max_requests Maximum requests per email (default 3).
         * @param string $email The email address.
         */
        $max_email_requests = apply_filters('switchboard_magic_login_max_email_requests', 3, $email);

        if ($email_requests && $email_requests >= $max_email_requests) {
            wp_send_json_error(['message' => __('A login link was recently sent to this email. Please check your inbox or try again shortly.', 'wpswitchboard')]);
        }

        // Check mode: 'login', 'register', or 'auto' (smart detection)
        $mode = isset($_POST['mode']) ? sanitize_text_field($_POST['mode']) : 'login';

        // Check if user exists
        $user = get_user_by('email', $email);

        // Always return success to prevent user enumeration
        // But only actually send email if user exists
        set_transient($rate_key, ($requests ? $requests + 1 : 1), 5 * MINUTE_IN_SECONDS);

        // Get registration settings
        $settings = get_option('switchboard_magic-login_settings', []);
        $enable_registration = isset($settings['enable_registration']) ? $settings['enable_registration'] === 'yes' : false;

        // AUTO MODE: Smart detection - login if user exists, register if not
        if ($mode === 'auto') {
            if ($user) {
                $mode = 'login'; // User exists, switch to login mode
            } elseif ($enable_registration) {
                $mode = 'register'; // User doesn't exist, registration enabled
            } else {
                // User doesn't exist and registration disabled - return generic success
                wp_send_json_success([
                    'message' => __('If an account exists with this email, a magic link has been sent.', 'wpswitchboard'),
                    'type' => 'generic',
                    'title' => __('Check your email', 'wpswitchboard'),
                    'subtitle' => __('If an account exists, we sent you a link.', 'wpswitchboard')
                ]);
            }
        }

        // Registration mode (explicit or from auto-detection)
        if ($mode === 'register') {
            if (!$enable_registration) {
                // Return success to prevent enumeration (registration is disabled silently)
                wp_send_json_success([
                    'message' => __('Check your email for next steps.', 'wpswitchboard'),
                    'type' => 'generic',
                    'title' => __('Check your email', 'wpswitchboard'),
                    'subtitle' => __('If registration is available, we sent you a link.', 'wpswitchboard')
                ]);
            }

            if ($user) {
                // User exists - in auto mode we already switched to login, but if explicit register mode:
                // don't reveal this, just silently return success
                wp_send_json_success([
                    'message' => __('Check your email for next steps.', 'wpswitchboard'),
                    'type' => 'generic',
                    'title' => __('Check your email', 'wpswitchboard'),
                    'subtitle' => __('Check your inbox for next steps.', 'wpswitchboard')
                ]);
            }

            set_transient($email_rate_key, ($email_requests ? $email_requests + 1 : 1), 2 * MINUTE_IN_SECONDS);
            $result = $this->create_registration_link($email, $redirect_to);

            // Check if registration link creation failed
            if (is_wp_error($result)) {
                wp_send_json_error(['message' => __('Unable to process your request. Please try again.', 'wpswitchboard')]);
                return;
            }

            // Personalized success message for new registration
            wp_send_json_success([
                'message' => __('Welcome! Check your email to create your account.', 'wpswitchboard'),
                'type' => 'register',
                'title' => __('Almost there!', 'wpswitchboard'),
                'subtitle' => __("We've sent a registration link to your email.", 'wpswitchboard')
            ]);
            return; // Ensure we don't fall through to login mode
        }

        // Login mode (explicit or from auto-detection)
        if ($user) {
            set_transient($email_rate_key, ($email_requests ? $email_requests + 1 : 1), 2 * MINUTE_IN_SECONDS);

            // Check if user role is allowed
            $settings = get_option('switchboard_magic-login_settings', []);
            $allowed_roles = isset($settings['allowed_roles']) ? $settings['allowed_roles'] : [];

            // Filter out invalid values (zeros, empty strings) from allowed_roles
            // This handles cases where checkboxes save '0' for unchecked items
            if (is_array($allowed_roles)) {
                $allowed_roles = array_filter($allowed_roles, function($role) {
                    return !empty($role) && $role !== '0' && $role !== 0;
                });
            }

            /**
             * Filter the allowed roles for magic login.
             *
             * @param array $allowed_roles Array of allowed role slugs. Empty means all roles allowed.
             * @param WP_User $user The user object.
             */
            $allowed_roles = apply_filters('switchboard_magic_login_allowed_roles', $allowed_roles, $user);

            $is_allowed = empty($allowed_roles); // If no roles specified, allow all
            if (!$is_allowed) {
                foreach ($user->roles as $role) {
                    if (in_array($role, $allowed_roles)) {
                        $is_allowed = true;
                        break;
                    }
                }
            }

            /**
             * Filter whether a specific user can use magic login.
             *
             * @param bool $is_allowed Whether the user is allowed.
             * @param WP_User $user The user object.
             */
            $is_allowed = apply_filters('switchboard_magic_login_user_allowed', $is_allowed, $user);

            if ($is_allowed) {
                /**
                 * Action fired before sending magic link email.
                 *
                 * @param WP_User $user The user object.
                 * @param string $redirect_to The redirect URL after login.
                 */
                do_action('switchboard_magic_login_before_send', $user, $redirect_to);

                // Check if SMS is enabled and requested
                $settings = get_option('switchboard_magic-login_settings', []);
                $sms_enabled = isset($settings['sms_enabled']) && $settings['sms_enabled'] === 'yes';
                $actual_delivery = ($delivery_method === 'sms' && $sms_enabled) ? 'sms' : 'email';

                $result = $this->create_and_send_magic_link($user, $redirect_to, false, $actual_delivery);

                // Check if magic link creation/sending failed
                if (is_wp_error($result)) {
                    wp_send_json_error(['message' => __('Unable to send login link. Please try again.', 'wpswitchboard')]);
                    return;
                }

                /**
                 * Action fired after sending magic link email.
                 *
                 * @param WP_User $user The user object.
                 * @param string $redirect_to The redirect URL after login.
                 */
                do_action('switchboard_magic_login_after_send', $user, $redirect_to);

                // Personalized success message based on delivery method
                $sent_via = isset($result['delivery_method']) ? $result['delivery_method'] : 'email';
                if ($sent_via === 'sms') {
                    wp_send_json_success([
                        'message' => __('Welcome back! Check your phone for a login code.', 'wpswitchboard'),
                        'type' => 'login',
                        'title' => __('Welcome back!', 'wpswitchboard'),
                        'subtitle' => __("We've sent a login code to your phone.", 'wpswitchboard'),
                        'delivery_method' => 'sms'
                    ]);
                } else {
                    wp_send_json_success([
                        'message' => __('Welcome back! Check your email for a login link.', 'wpswitchboard'),
                        'type' => 'login',
                        'title' => __('Welcome back!', 'wpswitchboard'),
                        'subtitle' => __("We've sent a login link to your email.", 'wpswitchboard'),
                        'delivery_method' => 'email'
                    ]);
                }
                return;
            }
        }

        // Generic response when no email was sent (user doesn't exist and registration disabled, or not allowed)
        wp_send_json_success([
            'message' => __('Check your email for next steps.', 'wpswitchboard'),
            'type' => 'generic',
            'title' => __('Check your email', 'wpswitchboard'),
            'subtitle' => __('If an account exists, we sent you a link.', 'wpswitchboard')
        ]);
    }

    /**
     * Create magic link and send email or SMS
     *
     * @param WP_User $user The user to send the link to
     * @param string $redirect_to Optional redirect URL after login
     * @param bool $use_code Whether to send a 6-digit code instead of a link
     * @param string $delivery_method 'email' or 'sms' (defaults to 'email')
     * @return array Array with 'login_url', 'login_code', 'expiry_minutes'
     */
    private function create_and_send_magic_link($user, $redirect_to = '', $use_code = false, $delivery_method = 'email') {
        global $wpdb;

        // Invalidate any existing unused links for this user
        $wpdb->update(
            $this->table_name,
            ['used_at' => gmdate('Y-m-d H:i:s')],
            ['user_id' => $user->ID, 'used_at' => null],
            ['%s'],
            ['%d', '%s']
        );

        // Generate secure token
        $token = bin2hex(random_bytes(32));
        $token_hash = hash('sha256', $token);

        // Generate 6-digit code for code login
        $login_code = $this->generate_login_code();
        $login_code_hash = hash('sha256', $login_code);

        // Get expiry from settings
        $settings = get_option('switchboard_magic-login_settings', []);
        $expiry_minutes = isset($settings['expiry_minutes']) ? intval($settings['expiry_minutes']) : $this->default_expiry;

        /**
         * Filter the magic link expiry time in minutes.
         *
         * @param int $expiry_minutes Expiry time in minutes.
         * @param WP_User $user The user object.
         */
        $expiry_minutes = apply_filters('switchboard_magic_login_expiry', $expiry_minutes, $user);
        $expiry_minutes = max(5, min(60, $expiry_minutes)); // Clamp between 5-60 minutes

        $expires_at = gmdate('Y-m-d H:i:s', time() + ($expiry_minutes * MINUTE_IN_SECONDS));

        // Save to database
        $inserted = $wpdb->insert(
            $this->table_name,
            [
                'user_id' => $user->ID,
                'token_hash' => $token_hash,
                'login_code' => $login_code_hash,
                'expires_at' => $expires_at,
                'created_at' => gmdate('Y-m-d H:i:s'),
                'ip_address' => $this->get_client_ip(),
                'user_agent' => $this->get_user_agent()
            ],
            ['%d', '%s', '%s', '%s', '%s', '%s', '%s']
        );

        if ($inserted === false) {
            return new WP_Error('db_error', __('Failed to create magic link. Please try again.', 'wpswitchboard'));
        }

        /**
         * Filter the base URL for magic login links.
         *
         * @param string $base_url The base login URL (wp_login_url()).
         * @param WP_User $user The user object.
         */
        $base_url = apply_filters('switchboard_magic_login_base_url', wp_login_url(), $user);

        // Build login URL
        $login_url = add_query_arg([
            'action' => 'switchboard_magic_verify',
            'token' => $token,
            'uid' => $user->ID
        ], $base_url);

        if (!empty($redirect_to)) {
            $login_url = add_query_arg('redirect_to', urlencode($redirect_to), $login_url);
        }

        /**
         * Filter the magic login URL before sending.
         *
         * @param string $login_url The login URL.
         * @param WP_User $user The user object.
         * @param string $redirect_to The redirect URL after login.
         */
        $login_url = apply_filters('switchboard_magic_login_url', $login_url, $user, $redirect_to);

        // Get settings for QR code and code login
        $include_qr = isset($settings['include_qr_code']) ? $settings['include_qr_code'] === 'yes' : true;
        $enable_code_login = isset($settings['enable_code_login']) ? $settings['enable_code_login'] === 'yes' : true;

        /**
         * Filter whether to include QR code in magic login emails.
         *
         * @param bool $include_qr Whether to include QR code.
         * @param WP_User $user The user object.
         */
        $include_qr = apply_filters('switchboard_magic_login_include_qr', $include_qr, $user);

        /**
         * Filter whether to include code login option.
         *
         * @param bool $enable_code_login Whether to include code login.
         * @param WP_User $user The user object.
         */
        $enable_code_login = apply_filters('switchboard_magic_login_enable_code', $enable_code_login, $user);

        // Send email
        $site_name = get_bloginfo('name');
        if (empty($site_name)) {
            $site_name = 'WordPress';
        }

        /**
         * Filter the magic login email subject.
         *
         * @param string $subject The email subject.
         * @param WP_User $user The user object.
         */
        $subject = apply_filters(
            'switchboard_magic_login_email_subject',
            sprintf(__('[%s] Your Login Link', 'wpswitchboard'), $site_name),
            $user
        );

        // Build HTML email with QR code
        $headers = ['Content-Type: text/html; charset=UTF-8'];

        // Generate QR code as base64 image
        $qr_code_html = '';
        if ($include_qr) {
            $qr_code_html = $this->generate_qr_code_html($login_url);
        }

        // Build code login section
        $code_login_html = '';
        if ($enable_code_login && !$use_code) {
            $code_login_url = add_query_arg([
                'action' => 'switchboard_magic_code',
                'uid' => $user->ID
            ], wp_login_url());
            if (!empty($redirect_to)) {
                $code_login_url = add_query_arg('redirect_to', urlencode($redirect_to), $code_login_url);
            }
            $code_login_html = sprintf(
                '<p style="margin-top: 20px; padding-top: 20px; border-top: 1px solid #e5e7eb; color: #6b7280; font-size: 14px;">%s <strong style="font-family: monospace; font-size: 18px; color: #1f2937; letter-spacing: 2px;">%s</strong></p>',
                __('Or enter this code:', 'wpswitchboard'),
                $login_code
            );
        }

        // If code-only mode, show only code
        if ($use_code) {
            $message = $this->build_code_only_email($user, $site_name, $login_code, $expiry_minutes);
        } else {
            $message = $this->build_magic_link_email($user, $site_name, $login_url, $expiry_minutes, $qr_code_html, $code_login_html);
        }

        /**
         * Filter the magic login email message.
         *
         * @param string $message The email message.
         * @param WP_User $user The user object.
         * @param string $login_url The login URL.
         * @param string $login_code The 6-digit login code.
         * @param int $expiry_minutes Expiry time in minutes.
         */
        $message = apply_filters('switchboard_magic_login_email_message', $message, $user, $login_url, $login_code, $expiry_minutes);

        /**
         * Filter the magic login email headers.
         *
         * @param array $headers The email headers.
         * @param WP_User $user The user object.
         */
        $headers = apply_filters('switchboard_magic_login_email_headers', $headers, $user);

        /**
         * Filter the recipient email address for magic login.
         *
         * @param string $email The recipient email address.
         * @param WP_User $user The user object.
         */
        $recipient_email = apply_filters('switchboard_magic_login_recipient_email', $user->user_email, $user);

        // Handle SMS delivery
        if ($delivery_method === 'sms') {
            $phone = $this->get_user_phone($user);
            if (!$phone) {
                // Fall back to email if no phone number
                $delivery_method = 'email';
            } else {
                $sms_result = $this->send_sms($phone, $login_code, $expiry_minutes);
                if (is_wp_error($sms_result)) {
                    // Fall back to email on SMS failure
                    $delivery_method = 'email';
                } else {
                    /**
                     * Action fired after magic login SMS is sent.
                     *
                     * @param WP_User $user The user object.
                     * @param string $login_code The login code.
                     * @param string $phone The phone number.
                     */
                    do_action('switchboard_magic_login_sms_sent_success', $user, $login_code, $phone);

                    return [
                        'login_url' => $login_url,
                        'login_code' => $login_code,
                        'expiry_minutes' => $expiry_minutes,
                        'sms_sent' => true,
                        'delivery_method' => 'sms'
                    ];
                }
            }
        }

        // Email delivery (default or fallback from SMS)
        $email_sent = wp_mail($recipient_email, $subject, $message, $headers);

        /**
         * Action fired after magic login email is sent.
         *
         * @param bool $email_sent Whether the email was sent successfully.
         * @param WP_User $user The user object.
         * @param string $login_url The login URL.
         * @param string $login_code The login code.
         */
        do_action('switchboard_magic_login_email_sent', $email_sent, $user, $login_url, $login_code);

        if (!$email_sent) {
            return new WP_Error('email_failed', __('Failed to send login email. Please try again.', 'wpswitchboard'));
        }

        return [
            'login_url' => $login_url,
            'login_code' => $login_code,
            'expiry_minutes' => $expiry_minutes,
            'email_sent' => true,
            'delivery_method' => 'email'
        ];
    }

    /**
     * Generate a login code
     */
    private function generate_login_code() {
        /**
         * Filter the login code length (number of digits).
         *
         * @param int $length The code length (default 6).
         */
        $code_length = apply_filters('switchboard_magic_login_code_length', $this->code_length);
        $code_length = max(4, min(10, $code_length)); // Clamp between 4-10 digits

        $max_value = pow(10, $code_length) - 1;
        return str_pad(random_int(0, $max_value), $code_length, '0', STR_PAD_LEFT);
    }

    /**
     * Send login code via SMS (Twilio)
     *
     * @param string $phone_number The recipient phone number
     * @param string $code The login code
     * @param int $expiry_minutes Code expiry in minutes
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    private function send_sms($phone_number, $code, $expiry_minutes) {
        $settings = get_option('switchboard_magic-login_settings', []);

        // Decrypt Twilio credentials
        $account_sid = isset($settings['twilio_account_sid']) ? $this->decrypt_credential($settings['twilio_account_sid']) : '';
        $auth_token = isset($settings['twilio_auth_token']) ? $this->decrypt_credential($settings['twilio_auth_token']) : '';
        $from_number = isset($settings['twilio_phone_number']) ? $settings['twilio_phone_number'] : '';
        $message_template = isset($settings['sms_message_template']) ? $settings['sms_message_template'] : __('Your login code for {site_name} is: {code}. This code expires in {expiry} minutes.', 'wpswitchboard');

        if (empty($account_sid) || empty($auth_token) || empty($from_number)) {
            return new WP_Error('twilio_not_configured', __('SMS service is not configured.', 'wpswitchboard'));
        }

        // Format the message
        $message = str_replace(
            ['{site_name}', '{code}', '{expiry}'],
            [get_bloginfo('name'), $code, $expiry_minutes],
            $message_template
        );

        /**
         * Filter the SMS message before sending.
         *
         * @param string $message The SMS message.
         * @param string $code The login code.
         * @param string $phone_number The recipient phone number.
         */
        $message = apply_filters('switchboard_magic_login_sms_message', $message, $code, $phone_number);

        // Twilio API endpoint
        $url = 'https://api.twilio.com/2010-04-01/Accounts/' . $account_sid . '/Messages.json';

        $response = wp_remote_post($url, [
            'headers' => [
                'Authorization' => 'Basic ' . base64_encode($account_sid . ':' . $auth_token),
                'Content-Type' => 'application/x-www-form-urlencoded'
            ],
            'body' => [
                'To' => $phone_number,
                'From' => $from_number,
                'Body' => $message
            ],
            'timeout' => 30
        ]);

        if (is_wp_error($response)) {
            return $response;
        }

        $body = json_decode(wp_remote_retrieve_body($response), true);
        $status_code = wp_remote_retrieve_response_code($response);

        if ($status_code >= 400) {
            $error_message = isset($body['message']) ? $body['message'] : __('SMS sending failed.', 'wpswitchboard');
            return new WP_Error('twilio_error', $error_message);
        }

        /**
         * Action fired after SMS is sent.
         *
         * @param string $phone_number The recipient phone number.
         * @param string $code The login code.
         * @param array $body The Twilio API response.
         */
        do_action('switchboard_magic_login_sms_sent', $phone_number, $code, $body);

        return true;
    }

    /**
     * Get user phone number from user meta
     *
     * @param WP_User $user The user object
     * @return string|false The phone number or false if not set
     */
    private function get_user_phone($user) {
        // First check the dedicated Magic Login phone field
        $magic_phone = get_user_meta($user->ID, 'switchboard_magic_login_phone', true);
        if (!empty($magic_phone)) {
            return $this->normalize_phone_number($magic_phone);
        }

        // Fallback: Check common phone meta keys
        $phone_keys = ['phone', 'phone_number', 'billing_phone', 'user_phone', 'mobile', 'mobile_phone'];

        /**
         * Filter the list of user meta keys to check for phone number.
         *
         * @param array $phone_keys Array of meta key names.
         * @param WP_User $user The user object.
         */
        $phone_keys = apply_filters('switchboard_magic_login_phone_meta_keys', $phone_keys, $user);

        foreach ($phone_keys as $key) {
            $phone = get_user_meta($user->ID, $key, true);
            if (!empty($phone)) {
                return $this->normalize_phone_number($phone);
            }
        }

        return false;
    }

    /**
     * Normalize phone number to E.164 format
     *
     * @param string $phone The phone number
     * @return string Normalized phone number
     */
    private function normalize_phone_number($phone) {
        // Remove all non-digit characters except +
        $phone = preg_replace('/[^\d+]/', '', $phone);

        // If doesn't start with +, assume it needs country code
        if (strpos($phone, '+') !== 0) {
            /**
             * Filter the default country code for phone numbers.
             *
             * @param string $country_code Default country code (e.g., '+1' for US).
             */
            $default_country_code = apply_filters('switchboard_magic_login_default_country_code', '+1');
            $phone = $default_country_code . ltrim($phone, '0');
        }

        return $phone;
    }

    /**
     * Handle registration via magic link
     *
     * @param string $email The user email
     * @param string $redirect_to Redirect URL after registration
     * @return array|WP_Error Result array or error
     */
    private function create_registration_link($email, $redirect_to = '') {
        $settings = get_option('switchboard_magic-login_settings', []);
        $enable_registration = isset($settings['enable_registration']) ? $settings['enable_registration'] === 'yes' : false;

        if (!$enable_registration) {
            return new WP_Error('registration_disabled', __('Registration is disabled.', 'wpswitchboard'));
        }

        // Check if user already exists
        if (get_user_by('email', $email)) {
            return new WP_Error('user_exists', __('An account with this email already exists.', 'wpswitchboard'));
        }

        // Generate registration token
        $token = bin2hex(random_bytes(32));
        $token_hash = hash('sha256', $token);

        // Store pending registration
        $expiry_minutes = isset($settings['expiry_minutes']) ? intval($settings['expiry_minutes']) : $this->default_expiry;
        $expires_at = time() + ($expiry_minutes * MINUTE_IN_SECONDS);

        $transient_set = set_transient(
            'switchboard_magic_register_' . $token_hash,
            [
                'email' => $email,
                'redirect_to' => $redirect_to,
                'created_at' => time()
            ],
            $expiry_minutes * MINUTE_IN_SECONDS
        );

        if (!$transient_set) {
            return new WP_Error('transient_failed', __('Failed to create registration link. Please try again.', 'wpswitchboard'));
        }

        // Build registration URL
        $registration_url = add_query_arg([
            'action' => 'switchboard_magic_register',
            'token' => $token
        ], wp_login_url());

        if (!empty($redirect_to)) {
            $registration_url = add_query_arg('redirect_to', urlencode($redirect_to), $registration_url);
        }

        /**
         * Filter the magic registration URL before sending.
         *
         * @param string $registration_url The registration URL.
         * @param string $email The user email.
         */
        $registration_url = apply_filters('switchboard_magic_login_registration_url', $registration_url, $email);

        // Send registration email
        $site_name = get_bloginfo('name');
        if (empty($site_name)) {
            $site_name = 'WordPress';
        }

        $subject = sprintf(__('[%s] Complete Your Registration', 'wpswitchboard'), $site_name);
        $message = $this->build_registration_email($email, $site_name, $registration_url, $expiry_minutes);

        $headers = ['Content-Type: text/html; charset=UTF-8'];
        $email_sent = wp_mail($email, $subject, $message, $headers);

        /**
         * Action fired after registration email is sent.
         *
         * @param bool $email_sent Whether the email was sent.
         * @param string $email The recipient email.
         * @param string $registration_url The registration URL.
         */
        do_action('switchboard_magic_login_registration_email_sent', $email_sent, $email, $registration_url);

        if (!$email_sent) {
            // Clean up the transient since email failed
            delete_transient('switchboard_magic_register_' . $token_hash);
            return new WP_Error('email_failed', __('Failed to send registration email. Please try again.', 'wpswitchboard'));
        }

        return [
            'registration_url' => $registration_url,
            'expiry_minutes' => $expiry_minutes
        ];
    }

    /**
     * Build HTML email for registration
     */
    private function build_registration_email($email, $site_name, $registration_url, $expiry_minutes) {
        return sprintf('
            <div style="max-width: 560px; margin: 0 auto; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif; color: #374151;">
                <div style="padding: 32px;">
                    <h2 style="margin: 0 0 8px; color: #1f2937; font-size: 24px;">%s</h2>
                    <p style="margin: 0 0 24px; color: #6b7280; font-size: 16px; line-height: 1.6;">%s</p>

                    <a href="%s" style="display: inline-block; padding: 14px 32px; background: #10b981; color: #ffffff; text-decoration: none; border-radius: 8px; font-weight: 600; font-size: 16px;">%s</a>

                    <p style="margin: 24px 0 0; color: #9ca3af; font-size: 13px; line-height: 1.6;">%s</p>

                    <hr style="margin: 24px 0; border: none; border-top: 1px solid #e5e7eb;">

                    <p style="margin: 0; color: #9ca3af; font-size: 12px;">%s %s</p>
                </div>
            </div>
        ',
            __('Complete Your Registration', 'wpswitchboard'),
            sprintf(__('Click the button below to create your account on %s:', 'wpswitchboard'), esc_html($site_name)),
            esc_url($registration_url),
            __('Create My Account', 'wpswitchboard'),
            sprintf(__('This link will expire in %d minutes. If you didn\'t request this, you can safely ignore this email.', 'wpswitchboard'), $expiry_minutes),
            __('This email was sent from', 'wpswitchboard'),
            esc_html(home_url())
        );
    }

    /**
     * Generate QR code HTML for email
     */
    private function generate_qr_code_html($url) {
        // Check if GD library is available
        if (!function_exists('imagepng')) {
            return '';
        }

        // Include QR code library
        $qr_lib = dirname(__FILE__) . '/../../assets/magic-login/class-qrcode.php';
        if (!file_exists($qr_lib)) {
            return '';
        }

        if (!class_exists('QRCode')) {
            require_once $qr_lib;
        }

        try {
            $qr = new QRCode($url, ['s' => 'qrm', 'w' => 200, 'h' => 200]);
            $image = $qr->render_image();

            if (!$image) {
                return '';
            }

            ob_start();
            imagepng($image);
            $image_data = ob_get_clean();
            imagedestroy($image);

            if (empty($image_data)) {
                return '';
            }

            $base64 = base64_encode($image_data);

            return sprintf(
                '<div style="text-align: center; margin: 24px 0; padding: 20px; background: #f9fafb; border-radius: 12px;">
                    <p style="margin: 0 0 12px; color: #6b7280; font-size: 14px;">%s</p>
                    <img src="data:image/png;base64,%s" alt="QR Code" style="width: 180px; height: 180px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
                </div>',
                __('Or scan this QR code with your phone:', 'wpswitchboard'),
                $base64
            );
        } catch (Exception $e) {
            return '';
        }
    }

    /**
     * Build HTML email for magic link
     */
    private function build_magic_link_email($user, $site_name, $login_url, $expiry_minutes, $qr_code_html = '', $code_login_html = '') {
        return sprintf('
            <div style="max-width: 560px; margin: 0 auto; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif; color: #374151;">
                <div style="padding: 32px;">
                    <h2 style="margin: 0 0 8px; color: #1f2937; font-size: 24px;">%s</h2>
                    <p style="margin: 0 0 24px; color: #6b7280; font-size: 16px; line-height: 1.6;">%s</p>

                    <a href="%s" style="display: inline-block; padding: 14px 32px; background: #3b82f6; color: #ffffff; text-decoration: none; border-radius: 8px; font-weight: 600; font-size: 16px;">%s</a>

                    %s

                    %s

                    <p style="margin: 24px 0 0; color: #9ca3af; font-size: 13px; line-height: 1.6;">%s</p>

                    <hr style="margin: 24px 0; border: none; border-top: 1px solid #e5e7eb;">

                    <p style="margin: 0; color: #9ca3af; font-size: 12px;">%s %s</p>
                </div>
            </div>
        ',
            /* translators: %s: user display name */
            sprintf(__('Hi %s,', 'wpswitchboard'), esc_html($user->display_name)),
            /* translators: %s: site name */
            sprintf(__('Click the button below to sign in to %s:', 'wpswitchboard'), esc_html($site_name)),
            esc_url($login_url),
            __('Sign In Now', 'wpswitchboard'),
            $qr_code_html,
            $code_login_html,
            /* translators: %d: minutes until expiry */
            sprintf(__('This link will expire in %d minutes. If you didn\'t request this, you can safely ignore this email.', 'wpswitchboard'), $expiry_minutes),
            __('This email was sent from', 'wpswitchboard'),
            esc_html(home_url())
        );
    }

    /**
     * Build HTML email for code-only login
     */
    private function build_code_only_email($user, $site_name, $login_code, $expiry_minutes) {
        return sprintf('
            <div style="max-width: 560px; margin: 0 auto; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif; color: #374151;">
                <div style="padding: 32px;">
                    <h2 style="margin: 0 0 8px; color: #1f2937; font-size: 24px;">%s</h2>
                    <p style="margin: 0 0 24px; color: #6b7280; font-size: 16px; line-height: 1.6;">%s</p>

                    <div style="text-align: center; padding: 32px; background: #f3f4f6; border-radius: 12px; margin: 24px 0;">
                        <p style="margin: 0 0 8px; color: #6b7280; font-size: 14px;">%s</p>
                        <p style="margin: 0; font-family: monospace; font-size: 36px; font-weight: 700; letter-spacing: 8px; color: #1f2937;">%s</p>
                    </div>

                    <p style="margin: 24px 0 0; color: #9ca3af; font-size: 13px; line-height: 1.6;">%s</p>

                    <hr style="margin: 24px 0; border: none; border-top: 1px solid #e5e7eb;">

                    <p style="margin: 0; color: #9ca3af; font-size: 12px;">%s %s</p>
                </div>
            </div>
        ',
            /* translators: %s: user display name */
            sprintf(__('Hi %s,', 'wpswitchboard'), esc_html($user->display_name)),
            /* translators: %s: site name */
            sprintf(__('Enter this code to sign in to %s:', 'wpswitchboard'), esc_html($site_name)),
            __('Your login code:', 'wpswitchboard'),
            esc_html($login_code),
            /* translators: %d: minutes until expiry */
            sprintf(__('This code will expire in %d minutes. If you didn\'t request this, you can safely ignore this email.', 'wpswitchboard'), $expiry_minutes),
            __('This email was sent from', 'wpswitchboard'),
            esc_html(home_url())
        );
    }

    /**
     * Process {{MAGIC_LINK}} placeholder in outgoing emails
     */
    public function process_magic_link_placeholder($args) {
        $settings = get_option('switchboard_magic-login_settings', []);
        $enable_auto_login = isset($settings['enable_auto_login']) ? $settings['enable_auto_login'] === 'yes' : false;

        if (!$enable_auto_login) {
            return $args;
        }

        // Check if message contains the placeholder
        if (strpos($args['message'], '{{MAGIC_LINK}}') === false &&
            strpos($args['message'], '{{MAGIC_LINK_BUTTON}}') === false &&
            strpos($args['message'], '{{MAGIC_LOGIN_QR}}') === false) {
            return $args;
        }

        // Get the recipient email
        $to = $args['to'];
        if (is_array($to)) {
            $to = $to[0];
        }

        // Extract email from "Name <email>" format if necessary
        if (preg_match('/<([^>]+)>/', $to, $matches)) {
            $to = $matches[1];
        }

        // Get user by email
        $user = get_user_by('email', sanitize_email($to));

        if (!$user) {
            // Remove placeholders if user doesn't exist
            $args['message'] = str_replace(['{{MAGIC_LINK}}', '{{MAGIC_LINK_BUTTON}}', '{{MAGIC_LOGIN_QR}}'], '', $args['message']);
            return $args;
        }

        // Check if user role is allowed
        $allowed_roles = isset($settings['allowed_roles']) ? $settings['allowed_roles'] : [];
        // Filter out invalid values (zeros, empty strings) from allowed_roles
        if (is_array($allowed_roles)) {
            $allowed_roles = array_filter($allowed_roles, function($role) {
                return !empty($role) && $role !== '0' && $role !== 0;
            });
        }
        $is_allowed = empty($allowed_roles); // Empty means all roles allowed
        if (!$is_allowed) {
            foreach ($user->roles as $role) {
                if (in_array($role, $allowed_roles)) {
                    $is_allowed = true;
                    break;
                }
            }
        }

        if (!$is_allowed) {
            $args['message'] = str_replace(['{{MAGIC_LINK}}', '{{MAGIC_LINK_BUTTON}}', '{{MAGIC_LOGIN_QR}}'], '', $args['message']);
            return $args;
        }

        /**
         * Filter to exclude specific emails from auto-login placeholder replacement.
         *
         * Return false to prevent magic link placeholder replacement for this email.
         *
         * @param bool $replace Whether to replace the placeholder (default true).
         * @param array $args The wp_mail args (to, subject, message, headers, attachments).
         * @param WP_User $user The user receiving the email.
         */
        $do_replace = apply_filters('switchboard_magic_login_replace_placeholder', true, $args, $user);
        if (!$do_replace) {
            $args['message'] = str_replace(['{{MAGIC_LINK}}', '{{MAGIC_LINK_BUTTON}}', '{{MAGIC_LOGIN_QR}}'], '', $args['message']);
            return $args;
        }

        // Generate magic link (without sending email since we're embedding in this email)
        global $wpdb;

        $token = bin2hex(random_bytes(32));
        $token_hash = hash('sha256', $token);
        $login_code = $this->generate_login_code();
        $login_code_hash = hash('sha256', $login_code);

        $expiry_minutes = isset($settings['expiry_minutes']) ? intval($settings['expiry_minutes']) : $this->default_expiry;
        $expiry_minutes = apply_filters('switchboard_magic_login_expiry', $expiry_minutes, $user);
        $expiry_minutes = max(5, min(60, $expiry_minutes));

        $expires_at = gmdate('Y-m-d H:i:s', time() + ($expiry_minutes * MINUTE_IN_SECONDS));

        $inserted = $wpdb->insert(
            $this->table_name,
            [
                'user_id' => $user->ID,
                'token_hash' => $token_hash,
                'login_code' => $login_code_hash,
                'expires_at' => $expires_at,
                'created_at' => gmdate('Y-m-d H:i:s'),
                'ip_address' => $this->get_client_ip(),
                'user_agent' => 'Auto-login email'
            ],
            ['%d', '%s', '%s', '%s', '%s', '%s', '%s']
        );

        // If insert failed, remove placeholders and return unmodified args
        if ($inserted === false) {
            $args['message'] = str_replace(['{{MAGIC_LINK}}', '{{MAGIC_LINK_BUTTON}}', '{{MAGIC_LOGIN_QR}}'], '', $args['message']);
            return $args;
        }

        $login_url = add_query_arg([
            'action' => 'switchboard_magic_verify',
            'token' => $token,
            'uid' => $user->ID
        ], wp_login_url());

        // Replace placeholders
        $args['message'] = str_replace('{{MAGIC_LINK}}', $login_url, $args['message']);

        // Button replacement
        $button_html = sprintf(
            '<a href="%s" style="display: inline-block; padding: 12px 24px; background: #3b82f6; color: #ffffff; text-decoration: none; border-radius: 6px; font-weight: 600;">%s</a>',
            esc_url($login_url),
            __('Sign In', 'wpswitchboard')
        );
        $args['message'] = str_replace('{{MAGIC_LINK_BUTTON}}', $button_html, $args['message']);

        // QR code replacement
        $qr_html = $this->generate_qr_code_html($login_url);
        $args['message'] = str_replace('{{MAGIC_LOGIN_QR}}', $qr_html, $args['message']);

        /**
         * Action fired when a magic link is auto-embedded in an email.
         *
         * @param WP_User $user The user object.
         * @param string $login_url The login URL.
         * @param array $args The wp_mail arguments.
         */
        do_action('switchboard_magic_login_auto_embedded', $user, $login_url, $args);

        return $args;
    }

    /**
     * Handle code login page (displays the code entry form)
     */
    public function handle_code_login_page() {
        // Add no-cache headers
        nocache_headers();

        $user_id = isset($_GET['uid']) ? intval($_GET['uid']) : 0;
        $redirect_to = isset($_GET['redirect_to']) ? esc_url_raw($_GET['redirect_to']) : admin_url();
        $error = isset($_GET['error']) ? sanitize_text_field($_GET['error']) : '';

        // If user is already logged in as the same user, just redirect
        if (is_user_logged_in()) {
            $current_user_id = get_current_user_id();
            if ($current_user_id === $user_id) {
                wp_safe_redirect($redirect_to);
                exit;
            }
            // Logged in as different user - log them out first
            wp_logout();
        }

        if (!$user_id) {
            wp_die(__('Invalid request.', 'wpswitchboard'), __('Error', 'wpswitchboard'), ['response' => 400]);
        }

        $user = get_userdata($user_id);
        if (!$user) {
            wp_die(__('Invalid user.', 'wpswitchboard'), __('Error', 'wpswitchboard'), ['response' => 400]);
        }

        // Security: Verify there's actually a pending code for this user (prevents user email enumeration)
        global $wpdb;
        $pending_code = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$this->table_name} WHERE user_id = %d AND login_code IS NOT NULL AND used_at IS NULL AND expires_at > %s",
            $user_id,
            gmdate('Y-m-d H:i:s')
        ));

        if (!$pending_code) {
            wp_die(
                '<h1>' . __('No Pending Code', 'wpswitchboard') . '</h1>' .
                '<p>' . __('There is no pending login code for this account, or it has expired.', 'wpswitchboard') . '</p>' .
                '<p><a href="' . esc_url(wp_login_url()) . '">' . __('Request a new login link', 'wpswitchboard') . '</a></p>',
                __('No Pending Code', 'wpswitchboard'),
                ['response' => 400, 'back_link' => false]
            );
        }

        // Display code entry form
        login_header(__('Enter Login Code', 'wpswitchboard'));
        ?>
        <style>
            .switchboard-code-form { max-width: 320px; margin: 0 auto; }
            .switchboard-code-input {
                width: 100%;
                padding: 16px;
                font-size: 24px;
                text-align: center;
                letter-spacing: 8px;
                font-family: monospace;
                border: 2px solid #dcdcde;
                border-radius: 4px;
                margin-bottom: 16px;
            }
            .switchboard-code-input:focus {
                border-color: #2271b1;
                outline: none;
                box-shadow: 0 0 0 1px #2271b1;
            }
            .switchboard-code-error {
                background: #fef2f2;
                border: 1px solid #fecaca;
                color: #dc2626;
                padding: 12px;
                border-radius: 4px;
                margin-bottom: 16px;
                text-align: center;
            }
        </style>

        <div class="switchboard-code-form">
            <p style="text-align: center; color: #50575e; margin-bottom: 20px;">
                <?php
                /* translators: %s: masked email address */
                printf(__('Enter the 6-digit code sent to %s', 'wpswitchboard'), $this->mask_email($user->user_email));
                ?>
            </p>

            <?php if ($error): ?>
                <div class="switchboard-code-error">
                    <?php
                    if ($error === 'invalid') {
                        _e('Invalid or expired code. Please try again.', 'wpswitchboard');
                    } elseif ($error === 'expired') {
                        _e('This code has expired. Please request a new one.', 'wpswitchboard');
                    } else {
                        echo esc_html($error);
                    }
                    ?>
                </div>
            <?php endif; ?>

            <form method="post" action="<?php echo esc_url(admin_url('admin-ajax.php')); ?>">
                <?php wp_nonce_field('switchboard_magic_code', 'switchboard_code_nonce'); ?>
                <input type="hidden" name="action" value="switchboard_verify_magic_code">
                <input type="hidden" name="user_id" value="<?php echo esc_attr($user_id); ?>">
                <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>">

                <input type="text" name="login_code" class="switchboard-code-input" maxlength="10" pattern="[0-9\s\-\.]{6,10}" placeholder="000000" autofocus required inputmode="numeric">

                <input type="submit" class="button button-primary button-large" style="width: 100%; height: 40px;" value="<?php esc_attr_e('Verify Code', 'wpswitchboard'); ?>">
            </form>

            <p style="text-align: center; margin-top: 20px;">
                <a href="<?php echo esc_url(wp_login_url()); ?>">&larr; <?php _e('Back to login', 'wpswitchboard'); ?></a>
            </p>
        </div>

        <?php
        login_footer();
        exit;
    }

    /**
     * Check if current request is an XMLHttpRequest
     */
    private function is_xhr_request() {
        return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
    }

    /**
     * Send error response (AJAX or redirect)
     */
    private function send_code_error($message, $user_id, $redirect_to) {
        if ($this->is_xhr_request()) {
            wp_send_json_error(['message' => $message]);
        } else {
            // Redirect back to code page with error
            $error_url = add_query_arg([
                'action' => 'switchboard_magic_code',
                'uid' => $user_id,
                'redirect_to' => urlencode($redirect_to),
                'error' => 'invalid'
            ], wp_login_url());
            wp_safe_redirect($error_url);
            exit;
        }
    }

    /**
     * AJAX: Verify magic code
     */
    public function ajax_verify_magic_code() {
        $user_id = intval($_POST['user_id'] ?? 0);
        $redirect_to = isset($_POST['redirect_to']) ? esc_url_raw($_POST['redirect_to']) : admin_url();

        // Verify nonce
        if (!wp_verify_nonce($_POST['switchboard_code_nonce'] ?? '', 'switchboard_magic_code')) {
            $this->send_code_error(__('Security check failed.', 'wpswitchboard'), $user_id, $redirect_to);
            return;
        }

        $code = sanitize_text_field($_POST['login_code'] ?? '');
        // Strip spaces, dashes, and other common separators for better UX
        $code = preg_replace('/[\s\-\.]/', '', $code);

        if (!$user_id || !$code) {
            $this->send_code_error(__('Invalid request.', 'wpswitchboard'), $user_id, $redirect_to);
            return;
        }

        // Validate code format
        if (!preg_match('/^[0-9]{6}$/', $code)) {
            $this->send_code_error(__('Invalid code format.', 'wpswitchboard'), $user_id, $redirect_to);
            return;
        }

        // CAPTCHA validation filter (reCAPTCHA, Turnstile, etc.)
        $captcha_valid = apply_filters('switchboard_magic_login_code_validate', true, $user_id);
        if (is_wp_error($captcha_valid)) {
            $this->send_code_error($captcha_valid->get_error_message(), $user_id, $redirect_to);
            return;
        }
        if ($captcha_valid === false) {
            $this->send_code_error(__('CAPTCHA verification failed. Please try again.', 'wpswitchboard'), $user_id, $redirect_to);
            return;
        }

        // Rate limiting
        $ip = $this->get_client_ip();
        $rate_key = 'switchboard_magic_code_' . md5($ip);
        $attempts = get_transient($rate_key);

        if ($attempts && $attempts >= 10) {
            $this->send_code_error(__('Too many attempts. Please try again later.', 'wpswitchboard'), $user_id, $redirect_to);
            return;
        }

        set_transient($rate_key, ($attempts ? $attempts + 1 : 1), 15 * MINUTE_IN_SECONDS);

        // Hash and look up code
        $code_hash = hash('sha256', $code);

        global $wpdb;
        $link = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$this->table_name} WHERE login_code = %s AND user_id = %d AND used_at IS NULL AND expires_at > %s",
            $code_hash,
            $user_id,
            gmdate('Y-m-d H:i:s')
        ));

        if (!$link) {
            $this->send_code_error(__('Invalid or expired code.', 'wpswitchboard'), $user_id, $redirect_to);
            return;
        }

        // Verify user exists
        $user = get_userdata($user_id);
        if (!$user) {
            $this->send_code_error(__('Invalid user.', 'wpswitchboard'), $user_id, $redirect_to);
            return;
        }

        // Mark link as used
        $updated = $wpdb->update(
            $this->table_name,
            ['used_at' => gmdate('Y-m-d H:i:s')],
            ['id' => $link->id],
            ['%s'],
            ['%d']
        );

        if ($updated === false) {
            $this->send_code_error(__('An error occurred. Please try again.', 'wpswitchboard'), $user_id, $redirect_to);
            return;
        }

        // Clear rate limit on success
        delete_transient($rate_key);

        /**
         * Action fired before logging in user via magic code.
         *
         * @param WP_User $user The user being logged in.
         * @param object $link The magic link database record.
         */
        do_action('switchboard_magic_login_before_login', $user, $link);

        // Log the user in
        wp_clear_auth_cookie();
        wp_set_current_user($user->ID);

        /** This filter is documented above */
        $remember = apply_filters('switchboard_magic_login_remember_user', false, $user);
        wp_set_auth_cookie($user->ID, $remember);

        /**
         * Action fired when a user logs in via magic code.
         *
         * @param string $user_login The user's login name.
         * @param WP_User $user The user object.
         */
        do_action('wp_login', $user->user_login, $user);
        do_action('switchboard_magic_login_code_success', $user);

        /** This filter is documented above */
        $redirect_to = apply_filters('switchboard_magic_login_redirect', $redirect_to, $user);
        $redirect_to = apply_filters('login_redirect', $redirect_to, $redirect_to, $user);

        // Check if this is an AJAX request or a regular form POST
        if ($this->is_xhr_request()) {
            wp_send_json_success(['redirect' => $redirect_to]);
        } else {
            // Regular form POST - redirect directly
            wp_safe_redirect($redirect_to);
            exit;
        }
    }

    /**
     * AJAX handler to send test email with magic link placeholders
     */
    public function ajax_send_test_magic_email() {
        // Check permissions
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Permission denied.', 'wpswitchboard')]);
        }

        // Verify nonce
        if (!wp_verify_nonce($_POST['nonce'] ?? '', 'switchboard_test_magic_email')) {
            wp_send_json_error(['message' => __('Security check failed.', 'wpswitchboard')]);
        }

        $current_user = wp_get_current_user();
        $to = $current_user->user_email;

        // Check settings to provide helpful feedback
        $settings = get_option('switchboard_magic-login_settings', []);
        $allowed_roles = isset($settings['allowed_roles']) ? $settings['allowed_roles'] : [];
        // Filter out invalid values (zeros, empty strings) from allowed_roles
        if (is_array($allowed_roles)) {
            $allowed_roles = array_filter($allowed_roles, function($role) {
                return !empty($role) && $role !== '0' && $role !== 0;
            });
        }

        // Ensure table exists
        $this->maybe_create_table();

        $subject = sprintf(__('[%s] Magic Login Placeholder Test', 'wpswitchboard'), get_bloginfo('name'));

        // Build HTML message directly (placeholders must not be escaped)
        $html_message = '<p>' . sprintf(
            esc_html__('Hi %s,', 'wpswitchboard'),
            esc_html($current_user->display_name)
        ) . '</p>';
        $html_message .= '<p>' . esc_html__('This is a test email to verify that Magic Login placeholders are working.', 'wpswitchboard') . '</p>';
        $html_message .= '<p><strong>=== MAGIC_LINK (plain URL) ===</strong><br>{{MAGIC_LINK}}</p>';
        $html_message .= '<p><strong>=== MAGIC_LINK_BUTTON (styled button) ===</strong><br>{{MAGIC_LINK_BUTTON}}</p>';
        $html_message .= '<p><strong>=== MAGIC_LOGIN_QR (QR code) ===</strong><br>{{MAGIC_LOGIN_QR}}</p>';
        $html_message .= '<p>' . esc_html__('If you see actual login links/buttons/QR codes above instead of the placeholder text, the feature is working correctly!', 'wpswitchboard') . '</p>';
        $html_message .= '<p><small>' . sprintf(esc_html__('Sent from %s', 'wpswitchboard'), esc_html(home_url())) . '</small></p>';

        // Set content type to HTML for the button and QR code
        $headers = ['Content-Type: text/html; charset=UTF-8'];

        $sent = wp_mail($to, $subject, $html_message, $headers);

        if ($sent) {
            wp_send_json_success([
                'message' => sprintf(__('Test email sent to %s', 'wpswitchboard'), $to)
            ]);
        } else {
            wp_send_json_error([
                'message' => __('Failed to send email. Check your WordPress email configuration.', 'wpswitchboard')
            ]);
        }
    }

    /**
     * Mask email address for display
     */
    private function mask_email($email) {
        $parts = explode('@', $email);
        if (count($parts) !== 2) {
            return $email;
        }

        $name = $parts[0];
        $domain = $parts[1];

        if (strlen($name) <= 2) {
            $masked_name = str_repeat('*', strlen($name));
        } else {
            $masked_name = substr($name, 0, 1) . str_repeat('*', strlen($name) - 2) . substr($name, -1);
        }

        return $masked_name . '@' . $domain;
    }

    /**
     * Handle magic registration verification
     */
    public function handle_registration_verify() {
        nocache_headers();

        $token = isset($_GET['token']) ? sanitize_text_field($_GET['token']) : '';
        $redirect_to = isset($_GET['redirect_to']) ? esc_url_raw($_GET['redirect_to']) : admin_url();

        // If user is already logged in, redirect to dashboard
        if (is_user_logged_in()) {
            wp_safe_redirect($redirect_to);
            exit;
        }

        if (empty($token)) {
            wp_die(__('Invalid registration link.', 'wpswitchboard'), __('Registration Error', 'wpswitchboard'), ['response' => 400]);
        }

        // Rate limiting to prevent token brute force
        $ip = $this->get_client_ip();
        $rate_key = 'switchboard_magic_register_' . md5($ip);
        $attempts = get_transient($rate_key);

        if ($attempts && $attempts >= 10) {
            wp_die(
                '<h1>' . __('Too Many Attempts', 'wpswitchboard') . '</h1>' .
                '<p>' . __('Please try again later.', 'wpswitchboard') . '</p>',
                __('Too Many Attempts', 'wpswitchboard'),
                ['response' => 429, 'back_link' => false]
            );
        }

        set_transient($rate_key, ($attempts ? $attempts + 1 : 1), 15 * MINUTE_IN_SECONDS);

        // Hash and look up token
        $token_hash = hash('sha256', $token);
        $registration_data = get_transient('switchboard_magic_register_' . $token_hash);

        if (!$registration_data) {
            wp_die(
                '<h1>' . __('Link Expired', 'wpswitchboard') . '</h1>' .
                '<p>' . __('This registration link has expired or has already been used.', 'wpswitchboard') . '</p>' .
                '<p><a href="' . esc_url(wp_login_url()) . '">' . __('Return to login', 'wpswitchboard') . '</a></p>',
                __('Link Expired', 'wpswitchboard'),
                ['response' => 410, 'back_link' => false]
            );
        }

        $email = $registration_data['email'];
        $saved_redirect = !empty($registration_data['redirect_to']) ? $registration_data['redirect_to'] : $redirect_to;

        // Check if user was created in meantime
        if (get_user_by('email', $email)) {
            delete_transient('switchboard_magic_register_' . $token_hash);
            wp_die(
                '<h1>' . __('Account Already Exists', 'wpswitchboard') . '</h1>' .
                '<p>' . __('An account with this email address already exists.', 'wpswitchboard') . '</p>' .
                '<p><a href="' . esc_url(wp_login_url()) . '">' . __('Return to login', 'wpswitchboard') . '</a></p>',
                __('Account Exists', 'wpswitchboard'),
                ['response' => 409, 'back_link' => false]
            );
        }

        // Create the user
        $settings = get_option('switchboard_magic-login_settings', []);
        $default_role = isset($settings['registration_default_role']) ? $settings['registration_default_role'] : 'subscriber';

        // Generate username from email
        $username = sanitize_user(current(explode('@', $email)), true);
        $original_username = $username;
        $suffix = 1;
        while (username_exists($username)) {
            $username = $original_username . $suffix;
            $suffix++;
        }

        // Generate random password
        $password = wp_generate_password(16, true, true);

        $user_id = wp_create_user($username, $password, $email);

        if (is_wp_error($user_id)) {
            wp_die(
                '<h1>' . __('Registration Failed', 'wpswitchboard') . '</h1>' .
                '<p>' . $user_id->get_error_message() . '</p>',
                __('Registration Failed', 'wpswitchboard'),
                ['response' => 500, 'back_link' => true]
            );
        }

        // Set user role
        $user = get_userdata($user_id);
        $user->set_role($default_role);

        // Delete the registration transient
        delete_transient('switchboard_magic_register_' . $token_hash);

        // Clear rate limit on successful registration
        delete_transient($rate_key);

        /**
         * Action fired after user is registered via magic link.
         *
         * @param int $user_id The new user ID.
         * @param string $email The user email.
         */
        do_action('switchboard_magic_login_user_registered', $user_id, $email);

        // Log the user in
        wp_clear_auth_cookie();
        wp_set_current_user($user_id);
        wp_set_auth_cookie($user_id, false);

        do_action('wp_login', $user->user_login, $user);

        /**
         * Filter the redirect URL after magic registration.
         *
         * @param string $redirect_to The redirect URL.
         * @param WP_User $user The new user.
         */
        $saved_redirect = apply_filters('switchboard_magic_login_registration_redirect', $saved_redirect, $user);

        wp_safe_redirect($saved_redirect);
        exit;
    }

    /**
     * Handle magic link verification
     */
    public function handle_magic_link_verify() {
        // Add no-cache headers to prevent CDN/proxy caching of magic login links
        nocache_headers();

        $token = isset($_GET['token']) ? sanitize_text_field($_GET['token']) : '';
        $user_id = isset($_GET['uid']) ? intval($_GET['uid']) : 0;
        $redirect_to = isset($_GET['redirect_to']) ? esc_url_raw($_GET['redirect_to']) : admin_url();

        // If user is already logged in as the same user, just redirect
        if (is_user_logged_in()) {
            $current_user_id = get_current_user_id();
            if ($current_user_id === $user_id) {
                // Already logged in as this user, just redirect
                wp_safe_redirect($redirect_to);
                exit;
            }
            // Logged in as different user - log them out first and continue
            wp_logout();
        }

        // Validate inputs
        if (!$token || !$user_id) {
            wp_die(
                '<h1>' . __('Invalid Link', 'wpswitchboard') . '</h1>' .
                '<p>' . __('This login link is invalid.', 'wpswitchboard') . '</p>',
                __('Invalid Link', 'wpswitchboard'),
                ['response' => 403, 'back_link' => true]
            );
        }

        // Validate token format
        if (!preg_match('/^[a-f0-9]{64}$/i', $token)) {
            wp_die(
                '<h1>' . __('Invalid Link', 'wpswitchboard') . '</h1>' .
                '<p>' . __('This login link is invalid.', 'wpswitchboard') . '</p>',
                __('Invalid Link', 'wpswitchboard'),
                ['response' => 403, 'back_link' => false]
            );
        }

        // Rate limiting
        $ip = $this->get_client_ip();
        $rate_key = 'switchboard_magic_verify_' . md5($ip);
        $attempts = get_transient($rate_key);

        if ($attempts && $attempts >= 10) {
            wp_die(
                '<h1>' . __('Too Many Attempts', 'wpswitchboard') . '</h1>' .
                '<p>' . __('Please try again later.', 'wpswitchboard') . '</p>',
                __('Too Many Attempts', 'wpswitchboard'),
                ['response' => 429, 'back_link' => false]
            );
        }

        set_transient($rate_key, ($attempts ? $attempts + 1 : 1), 15 * MINUTE_IN_SECONDS);

        // Hash the token and look it up
        $token_hash = hash('sha256', $token);

        global $wpdb;
        $link = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$this->table_name} WHERE token_hash = %s AND user_id = %d",
            $token_hash,
            $user_id
        ));

        // Generic error for security
        $generic_error = '<h1>' . __('Invalid or Expired Link', 'wpswitchboard') . '</h1>' .
            '<p>' . __('This login link is invalid, has expired, or has already been used.', 'wpswitchboard') . '</p>' .
            '<p><a href="' . esc_url(wp_login_url()) . '">' . __('Request a new link', 'wpswitchboard') . '</a></p>';

        if (!$link) {
            wp_die($generic_error, __('Invalid Link', 'wpswitchboard'), ['response' => 403, 'back_link' => false]);
        }

        // Check if already used
        if ($link->used_at) {
            wp_die($generic_error, __('Invalid Link', 'wpswitchboard'), ['response' => 403, 'back_link' => false]);
        }

        // Check expiry
        $expires_timestamp = strtotime($link->expires_at . ' UTC');
        if ($expires_timestamp === false || $expires_timestamp < time()) {
            wp_die($generic_error, __('Invalid Link', 'wpswitchboard'), ['response' => 403, 'back_link' => false]);
        }

        // Verify user exists
        $user = get_userdata($user_id);
        if (!$user) {
            wp_die($generic_error, __('Invalid Link', 'wpswitchboard'), ['response' => 403, 'back_link' => false]);
        }

        // Mark link as used
        $updated = $wpdb->update(
            $this->table_name,
            ['used_at' => gmdate('Y-m-d H:i:s')],
            ['id' => $link->id],
            ['%s'],
            ['%d']
        );

        if ($updated === false) {
            wp_die(
                '<h1>' . __('Error', 'wpswitchboard') . '</h1>' .
                '<p>' . __('An error occurred while processing your login. Please try again.', 'wpswitchboard') . '</p>',
                __('Error', 'wpswitchboard'),
                ['response' => 500, 'back_link' => true]
            );
        }

        // Clear rate limit on success
        delete_transient($rate_key);

        /**
         * Action fired before logging in user via magic link.
         *
         * @param WP_User $user The user being logged in.
         * @param object $link The magic link database record.
         */
        do_action('switchboard_magic_login_before_login', $user, $link);

        // Log the user in
        wp_clear_auth_cookie();
        wp_set_current_user($user->ID);

        /**
         * Filter whether to remember the user (persistent login cookie).
         *
         * @param bool $remember Whether to remember the user (default false).
         * @param WP_User $user The user being logged in.
         */
        $remember = apply_filters('switchboard_magic_login_remember_user', false, $user);
        wp_set_auth_cookie($user->ID, $remember);

        do_action('wp_login', $user->user_login, $user);

        /**
         * Action fired after successful magic link login.
         *
         * @param WP_User $user The logged in user.
         * @param object $link The magic link database record.
         */
        do_action('switchboard_magic_login_success', $user, $link);

        /**
         * Filter the redirect URL after magic link login.
         *
         * @param string $redirect_to The redirect URL.
         * @param WP_User $user The logged in user.
         */
        $redirect_to = apply_filters('switchboard_magic_login_redirect', $redirect_to, $user);

        // Also apply standard WP login_redirect filter for compatibility
        $redirect_to = apply_filters('login_redirect', $redirect_to, $redirect_to, $user);

        // Redirect
        wp_safe_redirect($redirect_to);
        exit;
    }

    /**
     * Get client IP
     */
    private function get_client_ip() {
        $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
        return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '0.0.0.0';
    }

    /**
     * Get user agent
     */
    private function get_user_agent() {
        return isset($_SERVER['HTTP_USER_AGENT']) ? substr(sanitize_text_field($_SERVER['HTTP_USER_AGENT']), 0, 255) : 'Unknown';
    }

    /**
     * Render CAPTCHA integration section in settings
     */
    private function render_captcha_integration_section() {
        // Check which CAPTCHA modules are active
        $simple_captcha_active = class_exists('SwitchboardSimpleCaptcha');
        $recaptcha_active = class_exists('SwitchboardGoogleReCaptcha');
        $turnstile_active = class_exists('SwitchboardCloudflareTurnstile');

        // Get their settings if active
        $simple_captcha_settings = $simple_captcha_active ? get_option('switchboard_simple-captcha_settings', []) : [];
        $recaptcha_settings = $recaptcha_active ? get_option('switchboard_google-recaptcha_settings', []) : [];
        $turnstile_settings = $turnstile_active ? get_option('switchboard_cloudflare-turnstile_settings', []) : [];

        // Check if protecting Magic Login
        $simple_captcha_protecting = $simple_captcha_active && !empty($simple_captcha_settings['protect_magic_login']);
        $recaptcha_protecting = $recaptcha_active && !empty($recaptcha_settings['protect_magic_login']);
        $turnstile_protecting = $turnstile_active && !empty($turnstile_settings['protect_magic_login']);

        // Check if keys are configured (Simple CAPTCHA doesn't need keys)
        $recaptcha_configured = !empty($recaptcha_settings['site_key']) && !empty($recaptcha_settings['secret_key']);
        $turnstile_configured = !empty($turnstile_settings['site_key']) && !empty($turnstile_settings['secret_key']);

        // Count active protections
        $active_count = ($simple_captcha_protecting ? 1 : 0) + ($recaptcha_protecting && $recaptcha_configured ? 1 : 0) + ($turnstile_protecting && $turnstile_configured ? 1 : 0);
        ?>
        <!-- CAPTCHA Protection Card -->
        <div class="sb-module-card sb-module-form-section" style="margin-bottom: 24px;">
            <div class="sb-module-card-header">
                <div class="sb-module-card-header-left">
                    <h2 class="sb-module-card-title"><?php _e('Spam Protection (CAPTCHA)', 'wpswitchboard'); ?></h2>
                    <p class="sb-module-card-desc"><?php _e('Protect Magic Login forms from bots and spam', 'wpswitchboard'); ?></p>
                </div>
            </div>
            <div class="sb-module-card-body">
                <?php if (!$simple_captcha_active && !$recaptcha_active && !$turnstile_active): ?>
                    <!-- No CAPTCHA modules active -->
                    <div class="sb-sp-info-box sb-sp-info-box-info">
                        <p class="sb-sp-description" style="margin: 0;">
                            <strong><?php _e('No CAPTCHA module enabled', 'wpswitchboard'); ?></strong><br>
                            <?php _e('Enable Simple CAPTCHA, Google reCAPTCHA, or Cloudflare Turnstile module to add spam protection to Magic Login forms.', 'wpswitchboard'); ?>
                        </p>
                        <p style="margin: 12px 0 0;">
                            <a href="<?php echo esc_url(admin_url('admin.php?page=switchboard&category=security')); ?>" class="button button-secondary">
                                <?php _e('View Security Modules', 'wpswitchboard'); ?>
                            </a>
                        </p>
                    </div>
                <?php else: ?>
                    <div style="display: flex; flex-direction: column; gap: 16px;">
                        <?php if ($simple_captcha_active): ?>
                            <div style="display: flex; align-items: center; justify-content: space-between; padding: 16px; background: <?php echo $simple_captcha_protecting ? '#f0fdf4' : '#f8fafc'; ?>; border: 1px solid <?php echo $simple_captcha_protecting ? '#bbf7d0' : '#e2e8f0'; ?>; border-radius: 8px;">
                                <div style="display: flex; align-items: center; gap: 12px;">
                                    <span class="dashicons dashicons-lock" style="font-size: 24px; color: #6366f1;"></span>
                                    <div>
                                        <strong style="color: #1e293b;"><?php _e('Simple CAPTCHA', 'wpswitchboard'); ?></strong>
                                        <?php if ($simple_captcha_protecting): ?>
                                            <p style="margin: 4px 0 0; font-size: 12px; color: #16a34a;"><?php _e('Protecting Magic Login forms', 'wpswitchboard'); ?></p>
                                        <?php else: ?>
                                            <p style="margin: 4px 0 0; font-size: 12px; color: #64748b;"><?php _e('Not enabled for Magic Login', 'wpswitchboard'); ?></p>
                                        <?php endif; ?>
                                    </div>
                                </div>
                                <a href="<?php echo esc_url(admin_url('admin.php?page=switchboard&module=simple-captcha')); ?>" class="button button-secondary" style="white-space: nowrap;">
                                    <?php echo $simple_captcha_protecting ? __('Configure', 'wpswitchboard') : __('Enable', 'wpswitchboard'); ?>
                                </a>
                            </div>
                        <?php endif; ?>

                        <?php if ($recaptcha_active): ?>
                            <div style="display: flex; align-items: center; justify-content: space-between; padding: 16px; background: <?php echo $recaptcha_protecting && $recaptcha_configured ? '#f0fdf4' : '#f8fafc'; ?>; border: 1px solid <?php echo $recaptcha_protecting && $recaptcha_configured ? '#bbf7d0' : '#e2e8f0'; ?>; border-radius: 8px;">
                                <div style="display: flex; align-items: center; gap: 12px;">
                                    <span class="dashicons dashicons-shield" style="font-size: 24px; width: 24px; height: 24px;"></span>
                                    <div>
                                        <strong style="color: #1e293b;"><?php _e('Google reCAPTCHA', 'wpswitchboard'); ?></strong>
                                        <?php if (!$recaptcha_configured): ?>
                                            <p style="margin: 4px 0 0; font-size: 12px; color: #f59e0b;"><?php _e('API keys not configured', 'wpswitchboard'); ?></p>
                                        <?php elseif ($recaptcha_protecting): ?>
                                            <p style="margin: 4px 0 0; font-size: 12px; color: #16a34a;"><?php _e('Protecting Magic Login forms', 'wpswitchboard'); ?></p>
                                        <?php else: ?>
                                            <p style="margin: 4px 0 0; font-size: 12px; color: #64748b;"><?php _e('Not enabled for Magic Login', 'wpswitchboard'); ?></p>
                                        <?php endif; ?>
                                    </div>
                                </div>
                                <a href="<?php echo esc_url(admin_url('admin.php?page=switchboard&module=google-recaptcha')); ?>" class="button button-secondary" style="white-space: nowrap;">
                                    <?php echo $recaptcha_protecting && $recaptcha_configured ? __('Configure', 'wpswitchboard') : __('Enable', 'wpswitchboard'); ?>
                                </a>
                            </div>
                        <?php endif; ?>

                        <?php if ($turnstile_active): ?>
                            <div style="display: flex; align-items: center; justify-content: space-between; padding: 16px; background: <?php echo $turnstile_protecting && $turnstile_configured ? '#f0fdf4' : '#f8fafc'; ?>; border: 1px solid <?php echo $turnstile_protecting && $turnstile_configured ? '#bbf7d0' : '#e2e8f0'; ?>; border-radius: 8px;">
                                <div style="display: flex; align-items: center; gap: 12px;">
                                    <span class="dashicons dashicons-cloud" style="font-size: 24px; width: 24px; height: 24px;"></span>
                                    <div>
                                        <strong style="color: #1e293b;"><?php _e('Cloudflare Turnstile', 'wpswitchboard'); ?></strong>
                                        <?php if (!$turnstile_configured): ?>
                                            <p style="margin: 4px 0 0; font-size: 12px; color: #f59e0b;"><?php _e('API keys not configured', 'wpswitchboard'); ?></p>
                                        <?php elseif ($turnstile_protecting): ?>
                                            <p style="margin: 4px 0 0; font-size: 12px; color: #16a34a;"><?php _e('Protecting Magic Login forms', 'wpswitchboard'); ?></p>
                                        <?php else: ?>
                                            <p style="margin: 4px 0 0; font-size: 12px; color: #64748b;"><?php _e('Not enabled for Magic Login', 'wpswitchboard'); ?></p>
                                        <?php endif; ?>
                                    </div>
                                </div>
                                <a href="<?php echo esc_url(admin_url('admin.php?page=switchboard&module=cloudflare-turnstile')); ?>" class="button button-secondary" style="white-space: nowrap;">
                                    <?php echo $turnstile_protecting && $turnstile_configured ? __('Configure', 'wpswitchboard') : __('Enable', 'wpswitchboard'); ?>
                                </a>
                            </div>
                        <?php endif; ?>

                        <?php if ($active_count > 1): ?>
                            <div class="sb-sp-info-box" style="background: #fef3c7; border-color: #fcd34d;">
                                <p class="sb-sp-description" style="margin: 0; color: #92400e;">
                                    <strong><?php _e('Note:', 'wpswitchboard'); ?></strong>
                                    <?php _e('Multiple CAPTCHA modules are enabled for Magic Login. Only one is needed - consider disabling others for better user experience.', 'wpswitchboard'); ?>
                                </p>
                            </div>
                        <?php endif; ?>
                    </div>
                <?php endif; ?>
            </div>
        </div>
        <?php
    }

    /**
     * Cleanup expired links
     */
    public function cleanup_expired() {
        global $wpdb;
        $wpdb->query($wpdb->prepare(
            "DELETE FROM {$this->table_name} WHERE expires_at < %s",
            gmdate('Y-m-d H:i:s', time() - DAY_IN_SECONDS) // Keep for 1 day after expiry for logging
        ));
    }

    /**
     * Register Gutenberg block
     */
    public function register_block() {
        if (!function_exists('register_block_type')) {
            return;
        }

        register_block_type('switchboard/magic-login', [
            'editor_script' => 'switchboard-magic-login-block',
            'render_callback' => [$this, 'render_block'],
            'attributes' => [
                'mode' => [
                    'type' => 'string',
                    'default' => 'auto'
                ],
                'title' => [
                    'type' => 'string',
                    'default' => ''
                ],
                'description' => [
                    'type' => 'string',
                    'default' => ''
                ],
                'buttonText' => [
                    'type' => 'string',
                    'default' => ''
                ],
                'redirect' => [
                    'type' => 'string',
                    'default' => ''
                ],
                'showPasswordLink' => [
                    'type' => 'boolean',
                    'default' => true
                ]
            ]
        ]);
    }

    /**
     * Enqueue block editor assets
     */
    public function enqueue_block_editor_assets() {
        wp_enqueue_script(
            'switchboard-magic-login-block',
            plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/magic-login/block.js',
            ['wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n'],
            '1.0.0',
            true
        );
    }

    /**
     * Render the block on frontend
     *
     * @param array $attributes Block attributes
     * @return string Block HTML
     */
    public function render_block($attributes) {
        $atts = [
            'mode' => isset($attributes['mode']) ? $attributes['mode'] : 'login',
            'title' => isset($attributes['title']) ? $attributes['title'] : '',
            'description' => isset($attributes['description']) ? $attributes['description'] : '',
            'button' => isset($attributes['buttonText']) ? $attributes['buttonText'] : '',
            'redirect' => isset($attributes['redirect']) ? $attributes['redirect'] : '',
            'show_password_link' => isset($attributes['showPasswordLink']) && $attributes['showPasswordLink'] ? 'yes' : 'no',
        ];

        return $this->render_shortcode($atts);
    }

    /**
     * Module activation
     */
    public function activate() {
        if (!wp_next_scheduled('switchboard_magic_links_cleanup')) {
            wp_schedule_event(time(), 'daily', 'switchboard_magic_links_cleanup');
        }
    }

    /**
     * Module deactivation
     */
    public function deactivate() {
        wp_clear_scheduled_hook('switchboard_magic_links_cleanup');
    }

    /**
     * Encrypt Twilio credentials before saving settings
     *
     * @param array $settings The settings being saved
     * @param string $module The module being saved
     * @return array Modified settings with encrypted credentials
     */
    public function encrypt_settings_before_save($settings, $module) {
        if ($module !== 'magic-login') {
            return $settings;
        }

        // Encrypt Twilio credentials before saving
        if (isset($settings['twilio_account_sid']) && !empty($settings['twilio_account_sid'])) {
            // Only encrypt if not already encrypted
            if (!$this->is_encrypted($settings['twilio_account_sid'])) {
                $settings['twilio_account_sid'] = $this->encrypt_credential($settings['twilio_account_sid']);
            }
        }
        if (isset($settings['twilio_auth_token']) && !empty($settings['twilio_auth_token'])) {
            if (!$this->is_encrypted($settings['twilio_auth_token'])) {
                $settings['twilio_auth_token'] = $this->encrypt_credential($settings['twilio_auth_token']);
            }
        }

        return $settings;
    }

    /**
     * Register data locations
     */
    public function register_data_locations() {
        return [
            'options' => ['switchboard_magic-login_settings'],
            'option_patterns' => [
                '_transient_switchboard_magic_rate_%',
                '_transient_timeout_switchboard_magic_rate_%',
                '_transient_switchboard_magic_email_%',
                '_transient_timeout_switchboard_magic_email_%',
                '_transient_switchboard_magic_verify_%',
                '_transient_timeout_switchboard_magic_verify_%',
            ],
            'tables' => ['switchboard_magic_links'],
            'post_meta' => [],
            'user_meta' => [
                'switchboard_magic_login_phone'
            ],
        ];
    }

    /**
     * Render module settings
     */
    public function render_settings($settings = []) {
        global $wpdb;

        $show_on_login = isset($settings['show_on_login']) ? $settings['show_on_login'] : 'yes';
        $expiry_minutes = isset($settings['expiry_minutes']) ? intval($settings['expiry_minutes']) : $this->default_expiry;
        $allowed_roles = isset($settings['allowed_roles']) ? $settings['allowed_roles'] : [];
        $shortcode_css = isset($settings['shortcode_css']) ? $settings['shortcode_css'] : '';

        // Advanced features
        $include_qr_code = isset($settings['include_qr_code']) ? $settings['include_qr_code'] : 'yes';
        $enable_code_login = isset($settings['enable_code_login']) ? $settings['enable_code_login'] : 'yes';
        $enable_auto_login = isset($settings['enable_auto_login']) ? $settings['enable_auto_login'] : 'no';

        // SMS Login (Twilio) - decrypt credentials for display
        $sms_enabled = isset($settings['sms_enabled']) ? $settings['sms_enabled'] : 'no';
        $twilio_account_sid = isset($settings['twilio_account_sid']) ? $this->decrypt_credential($settings['twilio_account_sid']) : '';
        $twilio_auth_token = isset($settings['twilio_auth_token']) ? $this->decrypt_credential($settings['twilio_auth_token']) : '';
        $twilio_phone_number = isset($settings['twilio_phone_number']) ? $settings['twilio_phone_number'] : '';
        $sms_message_template = isset($settings['sms_message_template']) ? $settings['sms_message_template'] : __('Your login code for {site_name} is: {code}. This code expires in {expiry} minutes.', 'wpswitchboard');

        // User Registration
        $enable_registration = isset($settings['enable_registration']) ? $settings['enable_registration'] : 'no';
        $registration_default_role = isset($settings['registration_default_role']) ? $settings['registration_default_role'] : 'subscriber';

        // Shortcode builder settings
        $sc_title = isset($settings['sc_title']) ? $settings['sc_title'] : __('Sign in with email', 'wpswitchboard');
        $sc_description = isset($settings['sc_description']) ? $settings['sc_description'] : __("Enter your email and we'll send you a link to sign in instantly.", 'wpswitchboard');
        $sc_button_text = isset($settings['sc_button_text']) ? $settings['sc_button_text'] : __('Send Login Link', 'wpswitchboard');
        $sc_placeholder = isset($settings['sc_placeholder']) ? $settings['sc_placeholder'] : __('email@example.com', 'wpswitchboard');
        $sc_redirect = isset($settings['sc_redirect']) ? $settings['sc_redirect'] : '';
        $sc_show_password_link = isset($settings['sc_show_password_link']) ? $settings['sc_show_password_link'] : 'yes';

        // Style settings
        $style_bg_color = isset($settings['style_bg_color']) ? $settings['style_bg_color'] : '#ffffff';
        $style_border_color = isset($settings['style_border_color']) ? $settings['style_border_color'] : '#e2e8f0';
        $style_border_radius = isset($settings['style_border_radius']) ? intval($settings['style_border_radius']) : 12;
        $style_title_color = isset($settings['style_title_color']) ? $settings['style_title_color'] : '#1e293b';
        $style_desc_color = isset($settings['style_desc_color']) ? $settings['style_desc_color'] : '#64748b';
        $style_input_border_color = isset($settings['style_input_border_color']) ? $settings['style_input_border_color'] : '#d1d5db';
        $style_input_border_radius = isset($settings['style_input_border_radius']) ? intval($settings['style_input_border_radius']) : 8;
        $style_button_bg = isset($settings['style_button_bg']) ? $settings['style_button_bg'] : '#3b82f6';
        $style_button_text_color = isset($settings['style_button_text_color']) ? $settings['style_button_text_color'] : '#ffffff';
        $style_button_radius = isset($settings['style_button_radius']) ? intval($settings['style_button_radius']) : 8;

        // Get all roles
        $roles = wp_roles()->roles;

        // Get stats
        $total_links = $wpdb->get_var("SELECT COUNT(*) FROM {$this->table_name}");
        $used_links = $wpdb->get_var("SELECT COUNT(*) FROM {$this->table_name} WHERE used_at IS NOT NULL");
        $active_links = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$this->table_name} WHERE used_at IS NULL AND expires_at > %s",
            gmdate('Y-m-d H:i:s')
        ));
        $unique_users = $wpdb->get_var("SELECT COUNT(DISTINCT user_id) FROM {$this->table_name} WHERE used_at IS NOT NULL");

        // Recent activity
        $recent_links = $wpdb->get_results(
            "SELECT m.*, u.display_name, u.user_email
             FROM {$this->table_name} m
             JOIN {$wpdb->users} u ON m.user_id = u.ID
             ORDER BY m.created_at DESC
             LIMIT 10"
        );
        ?>
        <input type="hidden" name="module" value="magic-login">

        <!-- How to Use Section -->
        <div class="sb-sp-info-box sb-sp-info-box-tip" style="margin-bottom: 24px; background: #fef3c7; border-color: #fcd34d;">
            <h4 class="sb-sp-heading-sm" style="color: #92400e;"><?php _e('How to Use Magic Login', 'wpswitchboard'); ?></h4>
            <div style="font-size: 13px; color: #78350f; line-height: 1.6;">
                <p style="margin: 0 0 12px;"><strong><?php _e('Option 1: Default Login Page', 'wpswitchboard'); ?></strong><br>
                <?php _e('Enable "Show on Login Form" below. Users will see "Email me a login link" button on wp-login.php', 'wpswitchboard'); ?></p>

                <p style="margin: 0 0 12px;"><strong><?php _e('Option 2: Custom Login Form (Shortcode)', 'wpswitchboard'); ?></strong><br>
                <?php _e('Add this shortcode anywhere on your site:', 'wpswitchboard'); ?></p>

                <div style="background: #fef9e7; padding: 12px; border-radius: 6px; font-family: monospace; margin-bottom: 12px;">
                    <code style="background: none; padding: 0;">[magic_login]</code><br><br>
                    <code style="background: none; padding: 0; font-size: 11px;">[magic_login title="Welcome Back" button="Get Magic Link" redirect="/dashboard"]</code>
                </div>

                <p style="margin: 0;"><strong><?php _e('Testing:', 'wpswitchboard'); ?></strong> <?php _e('Log out, go to your login page, and try the magic link option!', 'wpswitchboard'); ?></p>
            </div>
        </div>

        <!-- Stats Card -->
        <div class="sb-module-card sb-module-form-section" style="margin-bottom: 24px;">
            <div class="sb-module-card-header">
                <div class="sb-module-card-header-left">
                    <h2 class="sb-module-card-title"><?php _e('Magic Login Overview', 'wpswitchboard'); ?></h2>
                    <p class="sb-module-card-desc"><?php _e('Passwordless login statistics', 'wpswitchboard'); ?></p>
                </div>
            </div>
            <div class="sb-module-card-body">
                <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 16px;">
                    <div style="background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 20px; text-align: center;">
                        <div style="font-size: 32px; font-weight: 700; color: #2563eb;"><?php echo intval($total_links); ?></div>
                        <div style="font-size: 13px; color: #1e40af; margin-top: 4px;"><?php _e('Links Sent', 'wpswitchboard'); ?></div>
                    </div>
                    <div style="background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 20px; text-align: center;">
                        <div style="font-size: 32px; font-weight: 700; color: #16a34a;"><?php echo intval($used_links); ?></div>
                        <div style="font-size: 13px; color: #166534; margin-top: 4px;"><?php _e('Successful Logins', 'wpswitchboard'); ?></div>
                    </div>
                    <div style="background: #faf5ff; border: 1px solid #e9d5ff; border-radius: 8px; padding: 20px; text-align: center;">
                        <div style="font-size: 32px; font-weight: 700; color: #7c3aed;"><?php echo intval($unique_users); ?></div>
                        <div style="font-size: 13px; color: #6b21a8; margin-top: 4px;"><?php _e('Unique Users', 'wpswitchboard'); ?></div>
                    </div>
                    <div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 20px; text-align: center;">
                        <div style="font-size: 32px; font-weight: 700; color: #64748b;">
                            <?php echo $total_links > 0 ? round(($used_links / $total_links) * 100) : 0; ?>%
                        </div>
                        <div style="font-size: 13px; color: #64748b; margin-top: 4px;"><?php _e('Success Rate', 'wpswitchboard'); ?></div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Settings Card -->
        <div class="sb-module-card sb-module-form-section" style="margin-bottom: 24px;">
            <div class="sb-module-card-header">
                <div class="sb-module-card-header-left">
                    <h2 class="sb-module-card-title"><?php _e('Settings', 'wpswitchboard'); ?></h2>
                    <p class="sb-module-card-desc"><?php _e('Configure how magic login works', 'wpswitchboard'); ?></p>
                </div>
            </div>
            <div class="sb-module-card-body">
                <!-- Show on Login Toggle -->
                <div class="sb-module-option-item sb-module-toggle-item" style="margin-bottom: 24px;">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <strong class="sb-module-option-title"><?php _e('Show on Login Form', 'wpswitchboard'); ?></strong>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="setting_show_on_login" value="yes" <?php checked($show_on_login, 'yes'); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                        <p class="sb-module-option-text"><?php _e('Display the "Email me a login link" option on wp-login.php', 'wpswitchboard'); ?></p>
                    </div>
                </div>

                <!-- Expiry Time -->
                <div class="sb-sp-group sb-sp-field-horizontal" style="margin-bottom: 24px; padding-top: 24px; border-top: 1px solid #e5e7eb;">
                    <div class="sb-sp-field-horizontal-left">
                        <label for="setting_expiry_minutes" class="sb-sp-label"><?php _e('Link Expiry (Minutes)', 'wpswitchboard'); ?></label>
                        <p class="sb-sp-description"><?php _e('How long magic links remain valid. Shorter = more secure. (5-60 min)', 'wpswitchboard'); ?></p>
                    </div>
                    <input type="number" name="setting_expiry_minutes" id="setting_expiry_minutes" value="<?php echo esc_attr($expiry_minutes); ?>" min="5" max="60" class="sb-sp-input" style="width: 100px;">
                </div>

                <!-- Allowed Roles -->
                <div class="sb-sp-group" style="padding-top: 24px; border-top: 1px solid #e5e7eb;">
                    <label class="sb-sp-label" style="margin-bottom: 12px; display: block;"><?php _e('Allowed User Roles', 'wpswitchboard'); ?></label>
                    <p class="sb-sp-description" style="margin-bottom: 16px;"><?php _e('Which roles can use magic login. Leave all unchecked = allow everyone.', 'wpswitchboard'); ?></p>

                    <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px;">
                        <?php foreach ($roles as $role_key => $role): ?>
                            <label style="display: flex; align-items: center; gap: 10px; padding: 12px 16px; background: <?php echo in_array($role_key, $allowed_roles) ? 'var(--primary-50)' : '#f8fafc'; ?>; border: 1px solid <?php echo in_array($role_key, $allowed_roles) ? 'var(--primary-200)' : '#e2e8f0'; ?>; border-radius: 8px; cursor: pointer;">
                                <input type="checkbox" name="setting_allowed_roles[]" value="<?php echo esc_attr($role_key); ?>" <?php checked(in_array($role_key, $allowed_roles)); ?> style="width: 18px; height: 18px; accent-color: var(--primary-500);">
                                <span style="font-weight: 500; color: #374151;"><?php echo esc_html($role['name']); ?></span>
                            </label>
                        <?php endforeach; ?>
                    </div>
                </div>
            </div>
        </div>

        <?php $this->render_captcha_integration_section(); ?>

        <!-- Advanced Features Card -->
        <div class="sb-module-card sb-module-form-section" style="margin-bottom: 24px;">
            <div class="sb-module-card-header">
                <div class="sb-module-card-header-left">
                    <h2 class="sb-module-card-title"><?php _e('Advanced Features', 'wpswitchboard'); ?></h2>
                    <p class="sb-module-card-desc"><?php _e('QR codes, code login, and auto-login email placeholders', 'wpswitchboard'); ?></p>
                </div>
            </div>
            <div class="sb-module-card-body">
                <!-- Include QR Code Toggle -->
                <div class="sb-module-option-item sb-module-toggle-item" style="margin-bottom: 24px;">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <strong class="sb-module-option-title"><?php _e('Include QR Code in Emails', 'wpswitchboard'); ?></strong>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="setting_include_qr_code" value="yes" <?php checked($include_qr_code, 'yes'); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                        <p class="sb-module-option-text"><?php _e('Add a scannable QR code to magic login emails. Users can scan with their phone camera to login instantly.', 'wpswitchboard'); ?></p>
                    </div>
                </div>

                <!-- Enable Code Login Toggle -->
                <div class="sb-module-option-item sb-module-toggle-item" style="margin-bottom: 24px; padding-top: 24px; border-top: 1px solid #e5e7eb;">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <strong class="sb-module-option-title"><?php _e('Enable Code Login', 'wpswitchboard'); ?></strong>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="setting_enable_code_login" value="yes" <?php checked($enable_code_login, 'yes'); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                        <p class="sb-module-option-text"><?php _e('Include a 6-digit login code in emails as an alternative to clicking the link. Ideal for mobile users who cannot click links easily.', 'wpswitchboard'); ?></p>
                    </div>
                </div>

                <!-- Enable Auto-Login Placeholder Toggle -->
                <div class="sb-module-option-item sb-module-toggle-item" style="padding-top: 24px; border-top: 1px solid #e5e7eb;">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <strong class="sb-module-option-title"><?php _e('Auto-Login Email Placeholders', 'wpswitchboard'); ?></strong>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="setting_enable_auto_login" value="yes" <?php checked($enable_auto_login, 'yes'); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                        <p class="sb-module-option-text"><?php _e('Enable {{MAGIC_LINK}} placeholder in outgoing WordPress emails for one-click login.', 'wpswitchboard'); ?></p>
                    </div>

                    <!-- Placeholder Info Box (shown when enabled) -->
                    <div id="magic-link-placeholder-info" style="margin-top: 16px; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 16px; <?php echo $enable_auto_login !== 'yes' ? 'display: none;' : ''; ?>">
                        <p style="font-size: 13px; font-weight: 600; color: #1e40af; margin: 0 0 12px;"><?php _e('Available Placeholders:', 'wpswitchboard'); ?></p>
                        <div style="display: flex; flex-direction: column; gap: 8px;">
                            <div style="display: flex; align-items: flex-start; gap: 8px;">
                                <code style="background: #dbeafe; padding: 4px 8px; border-radius: 4px; font-size: 12px; white-space: nowrap;">{{MAGIC_LINK}}</code>
                                <span style="font-size: 12px; color: #3b82f6;"><?php _e('Plain URL for custom styling', 'wpswitchboard'); ?></span>
                            </div>
                            <div style="display: flex; align-items: flex-start; gap: 8px;">
                                <code style="background: #dbeafe; padding: 4px 8px; border-radius: 4px; font-size: 12px; white-space: nowrap;">{{MAGIC_LINK_BUTTON}}</code>
                                <span style="font-size: 12px; color: #3b82f6;"><?php _e('Styled button HTML', 'wpswitchboard'); ?></span>
                            </div>
                            <div style="display: flex; align-items: flex-start; gap: 8px;">
                                <code style="background: #dbeafe; padding: 4px 8px; border-radius: 4px; font-size: 12px; white-space: nowrap;">{{MAGIC_LOGIN_QR}}</code>
                                <span style="font-size: 12px; color: #3b82f6;"><?php _e('Scannable QR code image', 'wpswitchboard'); ?></span>
                            </div>
                        </div>
                        <p style="font-size: 12px; color: #64748b; margin: 12px 0 0; line-height: 1.5;"><?php _e('Add these placeholders to any email template (WooCommerce, newsletter plugins, etc.) and they\'ll be replaced with personalized login links for the recipient.', 'wpswitchboard'); ?></p>

                        <!-- Send Test Email Button -->
                        <div style="margin-top: 16px; padding-top: 16px; border-top: 1px dashed #bfdbfe; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
                            <button type="button" id="send-test-magic-email" class="sb-sp-button sb-sp-button-primary" style="padding: 8px 16px; font-size: 13px; border-radius: 6px; cursor: pointer;">
                                <?php _e('Send Test Email', 'wpswitchboard'); ?>
                            </button>
                            <span id="test-email-result" style="font-size: 13px; font-weight: 500;"></span>
                            <span style="font-size: 12px; color: #64748b; flex-basis: 100%;"><?php printf(__('Sends a test email to %s with all placeholders.', 'wpswitchboard'), '<strong>' . esc_html(wp_get_current_user()->user_email) . '</strong>'); ?></span>
                        </div>

                        <!-- Example Usage -->
                        <details style="margin-top: 16px;">
                            <summary style="font-size: 13px; font-weight: 600; color: #1e40af; cursor: pointer;"><?php _e('Example Usage', 'wpswitchboard'); ?></summary>
                            <div style="margin-top: 12px; background: #f8fafc; border-radius: 6px; padding: 12px; font-size: 12px;">
                                <p style="margin: 0 0 8px; color: #374151; font-weight: 500;"><?php _e('WooCommerce Order Email:', 'wpswitchboard'); ?></p>
                                <pre style="background: #1e293b; color: #e2e8f0; padding: 12px; border-radius: 4px; overflow-x: auto; margin: 0 0 12px; font-size: 11px; line-height: 1.5;">Hi {{customer.first_name}},

Your order #{{order.number}} is complete!

{{MAGIC_LINK_BUTTON}}

Or copy this link: {{MAGIC_LINK}}</pre>
                                <p style="margin: 0; color: #64748b; font-size: 11px;"><?php _e('The placeholders will be automatically replaced with working login links when the email is sent.', 'wpswitchboard'); ?></p>
                            </div>
                        </details>
                    </div>
                </div>
            </div>
        </div>

        <!-- SMS Login Card -->
        <div class="sb-module-card sb-module-form-section" style="margin-bottom: 24px;">
            <div class="sb-module-card-header">
                <div class="sb-module-card-header-left">
                    <h2 class="sb-module-card-title"><?php _e('SMS Login (Twilio)', 'wpswitchboard'); ?></h2>
                    <p class="sb-module-card-desc"><?php _e('Allow users to receive login codes via SMS', 'wpswitchboard'); ?></p>
                </div>
            </div>
            <div class="sb-module-card-body">
                <!-- Enable SMS Login Toggle -->
                <div class="sb-module-option-item sb-module-toggle-item" style="margin-bottom: 24px;">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <strong class="sb-module-option-title"><?php _e('Enable SMS Login', 'wpswitchboard'); ?></strong>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="setting_sms_enabled" id="setting_sms_enabled" value="yes" <?php checked($sms_enabled, 'yes'); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                        <p class="sb-module-option-text"><?php _e('Users can request a login code via SMS if they have a phone number in their profile.', 'wpswitchboard'); ?></p>
                    </div>
                </div>

                <!-- Twilio Settings (shown when enabled) -->
                <div id="twilio-settings" style="padding-top: 24px; border-top: 1px solid #e5e7eb; <?php echo $sms_enabled !== 'yes' ? 'display: none;' : ''; ?>">
                    <div class="sb-sp-info-box sb-sp-info-box-info" style="margin-bottom: 24px;">
                        <h4 class="sb-sp-heading-sm"><?php _e('Twilio Setup', 'wpswitchboard'); ?></h4>
                        <p class="sb-sp-description" style="margin: 0;">
                            <?php printf(__('Get your Twilio credentials from the <a href="%s" target="_blank">Twilio Console</a>. You\'ll need a verified phone number to send SMS.', 'wpswitchboard'), 'https://console.twilio.com/'); ?>
                        </p>
                    </div>

                    <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px;">
                        <div class="sb-sp-group">
                            <label for="setting_twilio_account_sid" class="sb-sp-label"><?php _e('Account SID', 'wpswitchboard'); ?></label>
                            <input type="text" name="setting_twilio_account_sid" id="setting_twilio_account_sid" value="<?php echo esc_attr($twilio_account_sid); ?>" class="sb-sp-input" placeholder="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" style="width: 100%;">
                        </div>
                        <div class="sb-sp-group">
                            <label for="setting_twilio_auth_token" class="sb-sp-label"><?php _e('Auth Token', 'wpswitchboard'); ?></label>
                            <input type="password" name="setting_twilio_auth_token" id="setting_twilio_auth_token" value="<?php echo esc_attr($twilio_auth_token); ?>" class="sb-sp-input" placeholder="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" style="width: 100%;">
                        </div>
                    </div>

                    <div class="sb-sp-group" style="margin-bottom: 20px;">
                        <label for="setting_twilio_phone_number" class="sb-sp-label"><?php _e('Twilio Phone Number', 'wpswitchboard'); ?></label>
                        <input type="text" name="setting_twilio_phone_number" id="setting_twilio_phone_number" value="<?php echo esc_attr($twilio_phone_number); ?>" class="sb-sp-input" placeholder="+1234567890" style="width: 300px;">
                        <p class="sb-sp-description"><?php _e('Your Twilio phone number in E.164 format (e.g., +1234567890)', 'wpswitchboard'); ?></p>
                    </div>

                    <div class="sb-sp-group" style="margin-bottom: 24px;">
                        <label for="setting_sms_message_template" class="sb-sp-label"><?php _e('SMS Message Template', 'wpswitchboard'); ?></label>
                        <textarea name="setting_sms_message_template" id="setting_sms_message_template" rows="2" class="sb-sp-input" style="width: 100%;"><?php echo esc_textarea($sms_message_template); ?></textarea>
                        <p class="sb-sp-description"><?php _e('Available placeholders: {site_name}, {code}, {expiry}', 'wpswitchboard'); ?></p>
                    </div>

                    <!-- Email Fallback Info -->
                    <div class="sb-sp-info-box" style="background: #f0fdf4; border-color: #bbf7d0; margin-bottom: 16px;">
                        <p class="sb-sp-description" style="margin: 0; color: #166534; font-size: 13px;">
                            <strong><?php _e('Automatic Email Fallback:', 'wpswitchboard'); ?></strong>
                            <?php _e('If SMS delivery fails (API error, or user has no phone number), the login code will automatically be sent via email instead.', 'wpswitchboard'); ?>
                        </p>
                    </div>

                    <!-- Phone Number Requirements -->
                    <div class="sb-sp-alert sb-sp-alert-warning" style="margin-bottom: 16px;">
                        <div class="sb-sp-alert-title"><?php _e('User Phone Number Required', 'wpswitchboard'); ?></div>
                        <div class="sb-sp-alert-text">
                            <?php _e('Users must have a phone number saved in their WordPress profile to receive SMS codes. Without a phone number, the system will automatically fall back to email delivery.', 'wpswitchboard'); ?>
                        </div>
                    </div>

                    <!-- Phone Format Info -->
                    <div class="sb-sp-info-box" style="background: #eff6ff; border-color: #bfdbfe;">
                        <p class="sb-sp-description" style="margin: 0 0 8px; color: #1e40af; font-size: 13px;">
                            <strong><?php _e('Phone Number Format (E.164):', 'wpswitchboard'); ?></strong>
                        </p>
                        <p class="sb-sp-description" style="margin: 0 0 8px; color: #3b82f6; font-size: 13px;">
                            <?php _e('Phone numbers must include the country code. Examples:', 'wpswitchboard'); ?>
                        </p>
                        <ul style="margin: 0; padding-left: 20px; color: #3b82f6; font-size: 12px;">
                            <li><code style="background: #dbeafe; padding: 2px 6px; border-radius: 3px;">+1 555 123 4567</code> <?php _e('(USA/Canada)', 'wpswitchboard'); ?></li>
                            <li><code style="background: #dbeafe; padding: 2px 6px; border-radius: 3px;">+44 7911 123456</code> <?php _e('(UK)', 'wpswitchboard'); ?></li>
                            <li><code style="background: #dbeafe; padding: 2px 6px; border-radius: 3px;">+91 98765 43210</code> <?php _e('(India)', 'wpswitchboard'); ?></li>
                        </ul>
                        <p class="sb-sp-description" style="margin: 8px 0 0; color: #64748b; font-size: 12px;">
                            <?php _e('The module checks these profile fields: phone, phone_number, billing_phone, user_phone, mobile, mobile_phone', 'wpswitchboard'); ?>
                        </p>
                    </div>
                </div>
            </div>
        </div>

        <script>
        (function() {
            var smsToggle = document.getElementById('setting_sms_enabled');
            var twilioSettings = document.getElementById('twilio-settings');
            if (smsToggle && twilioSettings) {
                smsToggle.addEventListener('change', function() {
                    twilioSettings.style.display = this.checked ? 'block' : 'none';
                });
            }
        })();
        </script>

        <!-- User Registration Card -->
        <?php $wp_registration_enabled = get_option('users_can_register'); ?>
        <div class="sb-module-card sb-module-form-section" style="margin-bottom: 24px;">
            <div class="sb-module-card-header">
                <div class="sb-module-card-header-left">
                    <h2 class="sb-module-card-title"><?php _e('User Registration', 'wpswitchboard'); ?></h2>
                    <p class="sb-module-card-desc"><?php _e('Allow new users to register via magic link or signup automatically', 'wpswitchboard'); ?></p>
                </div>
            </div>
            <div class="sb-module-card-body">
                <?php if (!$wp_registration_enabled): ?>
                <div class="sb-sp-alert sb-sp-alert-warning" style="margin-bottom: 20px;">
                    <div class="sb-sp-alert-title"><?php esc_html_e('WordPress Registration Disabled', 'wpswitchboard'); ?></div>
                    <div class="sb-sp-alert-text">
                        <?php _e('The global WordPress setting "Anyone can register" is currently disabled. To use Magic Link Registration or Smart Mode (which auto-registers new users), you need to enable it in', 'wpswitchboard'); ?>
                        <a href="<?php echo esc_url(admin_url('options-general.php#users_can_register')); ?>" style="color: inherit; text-decoration: underline;"><?php _e('Settings → General', 'wpswitchboard'); ?></a>.
                    </div>
                </div>
                <?php endif; ?>

                <!-- Enable Registration Toggle -->
                <div class="sb-module-option-item sb-module-toggle-item" style="margin-bottom: 24px;">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <strong class="sb-module-option-title"><?php _e('Enable Magic Link Registration', 'wpswitchboard'); ?></strong>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="setting_enable_registration" id="setting_enable_registration" value="yes" <?php checked($enable_registration, 'yes'); ?><?php echo !$wp_registration_enabled ? ' disabled' : ''; ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                        <p class="sb-module-option-text"><?php _e('New users can enter their email to receive a magic registration link. A new account will be created when they click the link.', 'wpswitchboard'); ?></p>
                    </div>
                </div>

                <!-- Registration Settings (shown when enabled) -->
                <div id="registration-settings" style="padding-top: 24px; border-top: 1px solid #e5e7eb; <?php echo $enable_registration !== 'yes' ? 'display: none;' : ''; ?>">
                    <div class="sb-sp-group">
                        <label for="setting_registration_default_role" class="sb-sp-label"><?php _e('Default Role for New Users', 'wpswitchboard'); ?></label>
                        <select name="setting_registration_default_role" id="setting_registration_default_role" class="sb-sp-select" style="width: 200px;">
                            <?php foreach ($roles as $role_key => $role): ?>
                                <option value="<?php echo esc_attr($role_key); ?>" <?php selected($registration_default_role, $role_key); ?>><?php echo esc_html($role['name']); ?></option>
                            <?php endforeach; ?>
                        </select>
                        <p class="sb-sp-description"><?php _e('The role assigned to users who register via magic link.', 'wpswitchboard'); ?></p>
                    </div>

                    <div class="sb-sp-info-box sb-sp-info-box-tip" style="margin-top: 20px; background: #eff6ff; border-color: #bfdbfe;">
                        <h4 class="sb-sp-heading-sm" style="color: #1e40af;"><?php _e('Registration Shortcode', 'wpswitchboard'); ?></h4>
                        <p class="sb-sp-description" style="margin: 0; color: #3b82f6;">
                            <?php _e('Use this shortcode for a dedicated registration form:', 'wpswitchboard'); ?><br>
                            <code style="background: #dbeafe; padding: 4px 8px; border-radius: 4px; margin-top: 8px; display: inline-block;">[magic_login mode="register"]</code>
                        </p>
                    </div>
                </div>
            </div>
        </div>

        <script>
        (function() {
            var regToggle = document.getElementById('setting_enable_registration');
            var regSettings = document.getElementById('registration-settings');
            if (regToggle && regSettings) {
                regToggle.addEventListener('change', function() {
                    regSettings.style.display = this.checked ? 'block' : 'none';
                });
            }
        })();
        </script>

        <!-- Shortcode Builder -->
        <div class="sb-module-card sb-module-form-section" style="margin-bottom: 24px;">
            <div class="sb-module-card-header">
                <div class="sb-module-card-header-left">
                    <h2 class="sb-module-card-title"><?php _e('Shortcode Builder', 'wpswitchboard'); ?></h2>
                    <p class="sb-module-card-desc"><?php _e('Build and customize the [magic_login] shortcode with live preview', 'wpswitchboard'); ?></p>
                </div>
            </div>
            <div class="sb-module-card-body" style="padding: 0;">

                <!-- Live Preview Section (Top) -->
                <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 48px 32px; position: relative; overflow: hidden;">
                    <!-- Background decoration -->
                    <div style="position: absolute; top: -50%; right: -20%; width: 400px; height: 400px; background: rgba(255,255,255,0.1); border-radius: 50%;"></div>
                    <div style="position: absolute; bottom: -30%; left: -10%; width: 300px; height: 300px; background: rgba(255,255,255,0.05); border-radius: 50%;"></div>

                    <div style="position: relative; z-index: 1; max-width: 420px; margin: 0 auto;">
                        <!-- Preview Container -->
                        <div id="sml-preview-container" style="background: <?php echo esc_attr($style_bg_color); ?>; border: 1px solid <?php echo esc_attr($style_border_color); ?>; border-radius: <?php echo esc_attr($style_border_radius); ?>px; padding: 36px; text-align: center; box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
                            <div id="sml-preview-title" style="font-size: 22px; font-weight: 600; color: <?php echo esc_attr($style_title_color); ?>; margin-bottom: 10px;"><?php echo esc_html($sc_title); ?></div>
                            <div id="sml-preview-desc" style="color: <?php echo esc_attr($style_desc_color); ?>; font-size: 14px; margin-bottom: 24px; line-height: 1.6;"><?php echo esc_html($sc_description); ?></div>
                            <input type="text" id="sml-preview-input" disabled placeholder="<?php echo esc_attr($sc_placeholder); ?>" style="width: 100%; padding: 14px 18px; border: 1px solid <?php echo esc_attr($style_input_border_color); ?>; border-radius: <?php echo esc_attr($style_input_border_radius); ?>px; margin-bottom: 14px; box-sizing: border-box; font-size: 15px; background: #fff; outline: none;">
                            <button id="sml-preview-button" disabled style="width: 100%; padding: 14px 20px; background: <?php echo esc_attr($style_button_bg); ?>; color: <?php echo esc_attr($style_button_text_color); ?>; border: none; border-radius: <?php echo esc_attr($style_button_radius); ?>px; font-weight: 600; font-size: 15px; cursor: pointer; transition: all 0.2s;"><?php echo esc_html($sc_button_text); ?></button>
                            <div id="sml-preview-password-link" style="margin-top: 18px; <?php echo $sc_show_password_link !== 'yes' ? 'display: none;' : ''; ?>">
                                <a href="#" onclick="return false;" style="color: <?php echo esc_attr($style_desc_color); ?>; font-size: 13px; text-decoration: none;"><?php _e('Use password instead', 'wpswitchboard'); ?> →</a>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Generated Shortcode (Below Preview) -->
                <div style="background: #1e293b; padding: 16px 24px; display: flex; align-items: center; justify-content: space-between; gap: 16px;">
                    <div style="display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0;">
                        <span style="font-size: 11px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap;"><?php _e('Shortcode', 'wpswitchboard'); ?></span>
                        <code id="sml-shortcode-output" style="color: #22d3ee; font-size: 13px; font-family: 'SF Mono', Monaco, Consolas, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">[magic_login]</code>
                    </div>
                    <button type="button" id="sml-copy-shortcode" style="background: #3b82f6; color: #fff; border: none; padding: 8px 16px; border-radius: 6px; font-size: 12px; font-weight: 500; cursor: pointer; white-space: nowrap; transition: background 0.15s;">
                        <?php _e('Copy', 'wpswitchboard'); ?>
                    </button>
                </div>

                <!-- Customizer Section (Bottom) -->
                <div style="padding: 32px;">
                    <!-- Tabs Navigation -->
                    <div style="display: flex; gap: 4px; margin-bottom: 28px; background: #f1f5f9; padding: 4px; border-radius: 10px;">
                        <button type="button" class="sml-tab-btn active" data-tab="content" style="flex: 1; padding: 10px 16px; border: none; background: #fff; border-radius: 8px; font-size: 13px; font-weight: 500; color: #1e293b; cursor: pointer; transition: all 0.15s; box-shadow: 0 1px 2px rgba(0,0,0,0.05);">
                            <?php _e('Content', 'wpswitchboard'); ?>
                        </button>
                        <button type="button" class="sml-tab-btn" data-tab="colors" style="flex: 1; padding: 10px 16px; border: none; background: transparent; border-radius: 8px; font-size: 13px; font-weight: 500; color: #64748b; cursor: pointer; transition: all 0.15s;">
                            <?php _e('Colors', 'wpswitchboard'); ?>
                        </button>
                        <button type="button" class="sml-tab-btn" data-tab="shape" style="flex: 1; padding: 10px 16px; border: none; background: transparent; border-radius: 8px; font-size: 13px; font-weight: 500; color: #64748b; cursor: pointer; transition: all 0.15s;">
                            <?php _e('Shape', 'wpswitchboard'); ?>
                        </button>
                        <button type="button" class="sml-tab-btn" data-tab="advanced" style="flex: 1; padding: 10px 16px; border: none; background: transparent; border-radius: 8px; font-size: 13px; font-weight: 500; color: #64748b; cursor: pointer; transition: all 0.15s;">
                            <?php _e('Advanced', 'wpswitchboard'); ?>
                        </button>
                    </div>

                    <!-- Content Tab -->
                    <div class="sml-tab-content" data-tab="content" style="display: block;">
                        <!-- Mode Selection -->
                        <div class="sb-sp-group" style="margin-bottom: 20px;">
                            <label for="setting_sc_mode" class="sb-sp-label" style="font-size: 13px; margin-bottom: 8px; display: block;"><?php _e('Form Mode', 'wpswitchboard'); ?></label>
                            <select name="setting_sc_mode" id="setting_sc_mode" class="sb-sp-select sml-builder-input" data-preview="mode" style="width: 100%; padding: 12px 14px; border-radius: 8px;">
                                <option value="auto"><?php _e('Smart — Login or Signup automatically', 'wpswitchboard'); ?></option>
                                <option value="login"><?php _e('Login Only — Existing users only', 'wpswitchboard'); ?></option>
                                <option value="register"><?php _e('Signup Only — New user registration', 'wpswitchboard'); ?></option>
                            </select>
                            <p id="sml-mode-description" style="margin: 8px 0 0; font-size: 12px; color: #64748b;"><?php _e('Smart mode: if email exists → login, if new email → signup. Perfect for a unified login/register form.', 'wpswitchboard'); ?></p>
                            <?php if (!$wp_registration_enabled): ?>
                            <div id="sml-mode-registration-notice" class="sb-sp-alert sb-sp-alert-warning" style="margin-top: 12px; padding: 10px 14px; display: none;">
                                <div class="sb-sp-alert-text" style="font-size: 12px;">
                                    <?php _e('This mode requires "Anyone can register" to be enabled in', 'wpswitchboard'); ?>
                                    <a href="<?php echo esc_url(admin_url('options-general.php#users_can_register')); ?>" target="_blank" style="color: inherit; text-decoration: underline;"><?php _e('Settings → General', 'wpswitchboard'); ?></a>.
                                </div>
                            </div>
                            <?php endif; ?>
                        </div>

                        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
                            <div class="sb-sp-group">
                                <label for="setting_sc_title" class="sb-sp-label" style="font-size: 13px; margin-bottom: 8px; display: block;"><?php _e('Title', 'wpswitchboard'); ?></label>
                                <input type="text" name="setting_sc_title" id="setting_sc_title" value="<?php echo esc_attr($sc_title); ?>" class="sb-sp-input sml-builder-input" data-preview="title" style="width: 100%; padding: 12px 14px; border-radius: 8px;">
                            </div>
                            <div class="sb-sp-group">
                                <label for="setting_sc_button_text" class="sb-sp-label" style="font-size: 13px; margin-bottom: 8px; display: block;"><?php _e('Button Text', 'wpswitchboard'); ?></label>
                                <input type="text" name="setting_sc_button_text" id="setting_sc_button_text" value="<?php echo esc_attr($sc_button_text); ?>" class="sb-sp-input sml-builder-input" data-preview="button" style="width: 100%; padding: 12px 14px; border-radius: 8px;">
                            </div>
                        </div>

                        <div class="sb-sp-group" style="margin-top: 20px;">
                            <label for="setting_sc_description" class="sb-sp-label" style="font-size: 13px; margin-bottom: 8px; display: block;"><?php _e('Description', 'wpswitchboard'); ?></label>
                            <textarea name="setting_sc_description" id="setting_sc_description" rows="2" class="sb-sp-input sml-builder-input" data-preview="description" style="width: 100%; padding: 12px 14px; border-radius: 8px; resize: vertical;"><?php echo esc_textarea($sc_description); ?></textarea>
                        </div>

                        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px;">
                            <div class="sb-sp-group">
                                <label for="setting_sc_placeholder" class="sb-sp-label" style="font-size: 13px; margin-bottom: 8px; display: block;"><?php _e('Input Placeholder', 'wpswitchboard'); ?></label>
                                <input type="text" name="setting_sc_placeholder" id="setting_sc_placeholder" value="<?php echo esc_attr($sc_placeholder); ?>" class="sb-sp-input sml-builder-input" data-preview="placeholder" style="width: 100%; padding: 12px 14px; border-radius: 8px;">
                            </div>
                            <div class="sb-sp-group">
                                <label for="setting_sc_redirect" class="sb-sp-label" style="font-size: 13px; margin-bottom: 8px; display: block;"><?php _e('Redirect After Login', 'wpswitchboard'); ?></label>
                                <input type="text" name="setting_sc_redirect" id="setting_sc_redirect" value="<?php echo esc_attr($sc_redirect); ?>" class="sb-sp-input" placeholder="/dashboard" style="width: 100%; padding: 12px 14px; border-radius: 8px;">
                            </div>
                        </div>

                        <div style="margin-top: 24px; padding: 16px; background: #f8fafc; border-radius: 10px;">
                            <label style="display: flex; align-items: center; gap: 12px; cursor: pointer;">
                                <input type="checkbox" name="setting_sc_show_password_link" value="yes" <?php checked($sc_show_password_link, 'yes'); ?> class="sml-builder-input" data-preview="passwordlink" style="width: 20px; height: 20px; accent-color: #3b82f6;">
                                <div>
                                    <span style="font-size: 14px; font-weight: 500; color: #1e293b;"><?php _e('Show "Use password instead" link', 'wpswitchboard'); ?></span>
                                    <p style="margin: 4px 0 0; font-size: 12px; color: #64748b;"><?php _e('Links to wp-login.php for traditional password login', 'wpswitchboard'); ?></p>
                                </div>
                            </label>
                        </div>
                    </div>

                    <!-- Colors Tab -->
                    <div class="sml-tab-content" data-tab="colors" style="display: none;">
                        <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;">
                            <!-- Container Colors -->
                            <div style="background: #f8fafc; border-radius: 12px; padding: 20px;">
                                <h5 style="margin: 0 0 16px; font-size: 12px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px;"><?php _e('Container', 'wpswitchboard'); ?></h5>

                                <div class="sb-sp-group" style="margin-bottom: 16px;">
                                    <label for="setting_style_bg_color" class="sb-sp-label" style="font-size: 12px; margin-bottom: 6px; display: block;"><?php _e('Background', 'wpswitchboard'); ?></label>
                                    <div style="display: flex; align-items: center; gap: 8px;">
                                        <input type="color" name="setting_style_bg_color" id="setting_style_bg_color" value="<?php echo esc_attr($style_bg_color); ?>" class="sml-builder-input" data-preview="bgcolor" style="width: 40px; height: 40px; padding: 0; border: 2px solid #e2e8f0; border-radius: 8px; cursor: pointer;">
                                        <input type="text" value="<?php echo esc_attr($style_bg_color); ?>" class="sb-sp-input sml-color-text" data-for="setting_style_bg_color" style="flex: 1; font-family: monospace; font-size: 12px; padding: 8px 10px; border-radius: 6px;">
                                    </div>
                                </div>

                                <div class="sb-sp-group">
                                    <label for="setting_style_border_color" class="sb-sp-label" style="font-size: 12px; margin-bottom: 6px; display: block;"><?php _e('Border', 'wpswitchboard'); ?></label>
                                    <div style="display: flex; align-items: center; gap: 8px;">
                                        <input type="color" name="setting_style_border_color" id="setting_style_border_color" value="<?php echo esc_attr($style_border_color); ?>" class="sml-builder-input" data-preview="bordercolor" style="width: 40px; height: 40px; padding: 0; border: 2px solid #e2e8f0; border-radius: 8px; cursor: pointer;">
                                        <input type="text" value="<?php echo esc_attr($style_border_color); ?>" class="sb-sp-input sml-color-text" data-for="setting_style_border_color" style="flex: 1; font-family: monospace; font-size: 12px; padding: 8px 10px; border-radius: 6px;">
                                    </div>
                                </div>
                            </div>

                            <!-- Text Colors -->
                            <div style="background: #f8fafc; border-radius: 12px; padding: 20px;">
                                <h5 style="margin: 0 0 16px; font-size: 12px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px;"><?php _e('Text', 'wpswitchboard'); ?></h5>

                                <div class="sb-sp-group" style="margin-bottom: 16px;">
                                    <label for="setting_style_title_color" class="sb-sp-label" style="font-size: 12px; margin-bottom: 6px; display: block;"><?php _e('Title', 'wpswitchboard'); ?></label>
                                    <div style="display: flex; align-items: center; gap: 8px;">
                                        <input type="color" name="setting_style_title_color" id="setting_style_title_color" value="<?php echo esc_attr($style_title_color); ?>" class="sml-builder-input" data-preview="titlecolor" style="width: 40px; height: 40px; padding: 0; border: 2px solid #e2e8f0; border-radius: 8px; cursor: pointer;">
                                        <input type="text" value="<?php echo esc_attr($style_title_color); ?>" class="sb-sp-input sml-color-text" data-for="setting_style_title_color" style="flex: 1; font-family: monospace; font-size: 12px; padding: 8px 10px; border-radius: 6px;">
                                    </div>
                                </div>

                                <div class="sb-sp-group">
                                    <label for="setting_style_desc_color" class="sb-sp-label" style="font-size: 12px; margin-bottom: 6px; display: block;"><?php _e('Description', 'wpswitchboard'); ?></label>
                                    <div style="display: flex; align-items: center; gap: 8px;">
                                        <input type="color" name="setting_style_desc_color" id="setting_style_desc_color" value="<?php echo esc_attr($style_desc_color); ?>" class="sml-builder-input" data-preview="desccolor" style="width: 40px; height: 40px; padding: 0; border: 2px solid #e2e8f0; border-radius: 8px; cursor: pointer;">
                                        <input type="text" value="<?php echo esc_attr($style_desc_color); ?>" class="sb-sp-input sml-color-text" data-for="setting_style_desc_color" style="flex: 1; font-family: monospace; font-size: 12px; padding: 8px 10px; border-radius: 6px;">
                                    </div>
                                </div>
                            </div>

                            <!-- Button Colors -->
                            <div style="background: #f8fafc; border-radius: 12px; padding: 20px;">
                                <h5 style="margin: 0 0 16px; font-size: 12px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px;"><?php _e('Button', 'wpswitchboard'); ?></h5>

                                <div class="sb-sp-group" style="margin-bottom: 16px;">
                                    <label for="setting_style_button_bg" class="sb-sp-label" style="font-size: 12px; margin-bottom: 6px; display: block;"><?php _e('Background', 'wpswitchboard'); ?></label>
                                    <div style="display: flex; align-items: center; gap: 8px;">
                                        <input type="color" name="setting_style_button_bg" id="setting_style_button_bg" value="<?php echo esc_attr($style_button_bg); ?>" class="sml-builder-input" data-preview="buttonbg" style="width: 40px; height: 40px; padding: 0; border: 2px solid #e2e8f0; border-radius: 8px; cursor: pointer;">
                                        <input type="text" value="<?php echo esc_attr($style_button_bg); ?>" class="sb-sp-input sml-color-text" data-for="setting_style_button_bg" style="flex: 1; font-family: monospace; font-size: 12px; padding: 8px 10px; border-radius: 6px;">
                                    </div>
                                </div>

                                <div class="sb-sp-group">
                                    <label for="setting_style_button_text_color" class="sb-sp-label" style="font-size: 12px; margin-bottom: 6px; display: block;"><?php _e('Text', 'wpswitchboard'); ?></label>
                                    <div style="display: flex; align-items: center; gap: 8px;">
                                        <input type="color" name="setting_style_button_text_color" id="setting_style_button_text_color" value="<?php echo esc_attr($style_button_text_color); ?>" class="sml-builder-input" data-preview="buttontextcolor" style="width: 40px; height: 40px; padding: 0; border: 2px solid #e2e8f0; border-radius: 8px; cursor: pointer;">
                                        <input type="text" value="<?php echo esc_attr($style_button_text_color); ?>" class="sb-sp-input sml-color-text" data-for="setting_style_button_text_color" style="flex: 1; font-family: monospace; font-size: 12px; padding: 8px 10px; border-radius: 6px;">
                                    </div>
                                </div>
                            </div>
                        </div>

                        <!-- Input Border Color -->
                        <div style="margin-top: 16px; background: #f8fafc; border-radius: 12px; padding: 20px;">
                            <div style="display: flex; align-items: center; gap: 24px;">
                                <h5 style="margin: 0; font-size: 12px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap;"><?php _e('Input Field', 'wpswitchboard'); ?></h5>
                                <div class="sb-sp-group" style="flex: 1; max-width: 200px;">
                                    <label for="setting_style_input_border_color" class="sb-sp-label" style="font-size: 12px; margin-bottom: 6px; display: block;"><?php _e('Border Color', 'wpswitchboard'); ?></label>
                                    <div style="display: flex; align-items: center; gap: 8px;">
                                        <input type="color" name="setting_style_input_border_color" id="setting_style_input_border_color" value="<?php echo esc_attr($style_input_border_color); ?>" class="sml-builder-input" data-preview="inputborder" style="width: 40px; height: 40px; padding: 0; border: 2px solid #e2e8f0; border-radius: 8px; cursor: pointer;">
                                        <input type="text" value="<?php echo esc_attr($style_input_border_color); ?>" class="sb-sp-input sml-color-text" data-for="setting_style_input_border_color" style="flex: 1; font-family: monospace; font-size: 12px; padding: 8px 10px; border-radius: 6px;">
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <!-- Shape Tab -->
                    <div class="sml-tab-content" data-tab="shape" style="display: none;">
                        <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px;">
                            <div style="background: #f8fafc; border-radius: 12px; padding: 24px; text-align: center;">
                                <div style="width: 48px; height: 48px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 12px; margin: 0 auto 16px; display: flex; align-items: center; justify-content: center;">
                                    <span style="font-size: 20px;">▢</span>
                                </div>
                                <label for="setting_style_border_radius" class="sb-sp-label" style="font-size: 13px; font-weight: 600; color: #1e293b; display: block; margin-bottom: 12px;"><?php _e('Container', 'wpswitchboard'); ?></label>
                                <input type="range" name="setting_style_border_radius" id="setting_style_border_radius" value="<?php echo esc_attr($style_border_radius); ?>" min="0" max="32" class="sml-builder-input" data-preview="borderradius" style="width: 100%; accent-color: #667eea;">
                                <div class="sml-radius-value" style="margin-top: 8px; font-size: 14px; font-weight: 600; color: #667eea;"><?php echo $style_border_radius; ?>px</div>
                            </div>

                            <div style="background: #f8fafc; border-radius: 12px; padding: 24px; text-align: center;">
                                <div style="width: 48px; height: 48px; background: #fff; border: 2px solid #d1d5db; border-radius: 8px; margin: 0 auto 16px; display: flex; align-items: center; justify-content: center;">
                                    <span style="font-size: 16px; color: #9ca3af;">|</span>
                                </div>
                                <label for="setting_style_input_border_radius" class="sb-sp-label" style="font-size: 13px; font-weight: 600; color: #1e293b; display: block; margin-bottom: 12px;"><?php _e('Input Field', 'wpswitchboard'); ?></label>
                                <input type="range" name="setting_style_input_border_radius" id="setting_style_input_border_radius" value="<?php echo esc_attr($style_input_border_radius); ?>" min="0" max="24" class="sml-builder-input" data-preview="inputradius" style="width: 100%; accent-color: #667eea;">
                                <div class="sml-radius-value" style="margin-top: 8px; font-size: 14px; font-weight: 600; color: #667eea;"><?php echo $style_input_border_radius; ?>px</div>
                            </div>

                            <div style="background: #f8fafc; border-radius: 12px; padding: 24px; text-align: center;">
                                <div style="width: 48px; height: 48px; background: #3b82f6; border-radius: 8px; margin: 0 auto 16px; display: flex; align-items: center; justify-content: center;">
                                    <span style="font-size: 14px; color: #fff;">→</span>
                                </div>
                                <label for="setting_style_button_radius" class="sb-sp-label" style="font-size: 13px; font-weight: 600; color: #1e293b; display: block; margin-bottom: 12px;"><?php _e('Button', 'wpswitchboard'); ?></label>
                                <input type="range" name="setting_style_button_radius" id="setting_style_button_radius" value="<?php echo esc_attr($style_button_radius); ?>" min="0" max="24" class="sml-builder-input" data-preview="buttonradius" style="width: 100%; accent-color: #667eea;">
                                <div class="sml-radius-value" style="margin-top: 8px; font-size: 14px; font-weight: 600; color: #667eea;"><?php echo $style_button_radius; ?>px</div>
                            </div>
                        </div>

                        <!-- Quick Presets -->
                        <div style="margin-top: 24px; padding: 20px; background: #f8fafc; border-radius: 12px;">
                            <h5 style="margin: 0 0 16px; font-size: 12px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px;"><?php _e('Quick Presets', 'wpswitchboard'); ?></h5>
                            <div style="display: flex; gap: 12px;">
                                <button type="button" class="sml-preset-btn" data-container="0" data-input="0" data-button="0" style="padding: 10px 20px; border: 2px solid #e2e8f0; background: #fff; border-radius: 4px; font-size: 13px; font-weight: 500; color: #374151; cursor: pointer;">
                                    Sharp
                                </button>
                                <button type="button" class="sml-preset-btn" data-container="8" data-input="6" data-button="6" style="padding: 10px 20px; border: 2px solid #e2e8f0; background: #fff; border-radius: 8px; font-size: 13px; font-weight: 500; color: #374151; cursor: pointer;">
                                    Soft
                                </button>
                                <button type="button" class="sml-preset-btn" data-container="16" data-input="12" data-button="12" style="padding: 10px 20px; border: 2px solid #e2e8f0; background: #fff; border-radius: 16px; font-size: 13px; font-weight: 500; color: #374151; cursor: pointer;">
                                    Rounded
                                </button>
                                <button type="button" class="sml-preset-btn" data-container="24" data-input="20" data-button="50" style="padding: 10px 20px; border: 2px solid #e2e8f0; background: #fff; border-radius: 24px; font-size: 13px; font-weight: 500; color: #374151; cursor: pointer;">
                                    Pill
                                </button>
                            </div>
                        </div>
                    </div>

                    <!-- Advanced Tab -->
                    <div class="sml-tab-content" data-tab="advanced" style="display: none;">
                        <div style="background: #fffbeb; border: 1px solid #fcd34d; border-radius: 10px; padding: 16px; margin-bottom: 24px;">
                            <div style="display: flex; align-items: flex-start; gap: 12px;">
                                <span class="dashicons dashicons-lightbulb" style="font-size: 18px; color: #f59e0b;"></span>
                                <div>
                                    <p style="margin: 0; font-size: 13px; color: #92400e; line-height: 1.5;">
                                        <?php _e('Use custom CSS for additional styling beyond the visual options above. Target these classes:', 'wpswitchboard'); ?>
                                    </p>
                                    <code style="display: inline-block; margin-top: 8px; padding: 4px 8px; background: rgba(0,0,0,0.05); border-radius: 4px; font-size: 11px; color: #78350f;">
                                        .switchboard-magic-login-form, .sml-title, .sml-desc, .sml-input, .sml-button
                                    </code>
                                </div>
                            </div>
                        </div>

                        <style>
                            #setting_shortcode_css::placeholder {
                                opacity: 0.4;
                                color: #64748b;
                            }
                        </style>
                        <textarea name="setting_shortcode_css" id="setting_shortcode_css" rows="10" class="sb-sp-input" style="width: 100%; font-family: 'SF Mono', Monaco, Consolas, monospace; font-size: 13px; line-height: 1.6; padding: 16px; border-radius: 10px; resize: vertical;" placeholder="/* Custom hover effect */
.switchboard-magic-login-form .sml-button:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}

/* Custom focus state */
.switchboard-magic-login-form .sml-input:focus {
    box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1);
}"><?php echo esc_textarea($shortcode_css); ?></textarea>
                    </div>
                </div>
            </div>
        </div>

        <!-- Tab Switching JavaScript -->
        <style>
            .sml-tab-btn:hover:not(.active) {
                background: rgba(255,255,255,0.5) !important;
                color: #475569 !important;
            }
            .sml-preset-btn:hover {
                border-color: #667eea !important;
                background: #f5f3ff !important;
            }
        </style>

        <!-- Shortcode Builder JavaScript -->
        <script>
        (function() {
            // Elements
            var previewContainer = document.getElementById('sml-preview-container');
            var previewTitle = document.getElementById('sml-preview-title');
            var previewDesc = document.getElementById('sml-preview-desc');
            var previewInput = document.getElementById('sml-preview-input');
            var previewButton = document.getElementById('sml-preview-button');
            var previewPasswordLink = document.getElementById('sml-preview-password-link');
            var shortcodeOutput = document.getElementById('sml-shortcode-output');

            // Defaults for each mode
            var modeDefaults = {
                auto: {
                    title: '<?php echo esc_js(__('Continue with email', 'wpswitchboard')); ?>',
                    description: '<?php echo esc_js(__('Enter your email to sign in or create an account.', 'wpswitchboard')); ?>',
                    button: '<?php echo esc_js(__('Continue', 'wpswitchboard')); ?>'
                },
                login: {
                    title: '<?php echo esc_js(__('Sign in with email', 'wpswitchboard')); ?>',
                    description: '<?php echo esc_js(__("Enter your email and we'll send you a link to sign in instantly.", 'wpswitchboard')); ?>',
                    button: '<?php echo esc_js(__('Send Login Link', 'wpswitchboard')); ?>'
                },
                register: {
                    title: '<?php echo esc_js(__('Create an account', 'wpswitchboard')); ?>',
                    description: '<?php echo esc_js(__("Enter your email and we'll send you a link to create your account.", 'wpswitchboard')); ?>',
                    button: '<?php echo esc_js(__('Send Registration Link', 'wpswitchboard')); ?>'
                }
            };
            var defaults = modeDefaults.login; // Base defaults for shortcode comparison
            var currentMode = 'auto';

            // Tab switching
            document.querySelectorAll('.sml-tab-btn').forEach(function(btn) {
                btn.addEventListener('click', function() {
                    var tabName = this.dataset.tab;

                    // Update button states
                    document.querySelectorAll('.sml-tab-btn').forEach(function(b) {
                        b.classList.remove('active');
                        b.style.background = 'transparent';
                        b.style.color = '#64748b';
                        b.style.boxShadow = 'none';
                    });
                    this.classList.add('active');
                    this.style.background = '#fff';
                    this.style.color = '#1e293b';
                    this.style.boxShadow = '0 1px 2px rgba(0,0,0,0.05)';

                    // Show/hide content
                    document.querySelectorAll('.sml-tab-content').forEach(function(content) {
                        content.style.display = content.dataset.tab === tabName ? 'block' : 'none';
                    });
                });
            });

            // Update preview function
            function updatePreview() {
                var mode = document.getElementById('setting_sc_mode').value;
                var title = document.getElementById('setting_sc_title').value;
                var desc = document.getElementById('setting_sc_description').value;
                var button = document.getElementById('setting_sc_button_text').value;
                var placeholder = document.getElementById('setting_sc_placeholder').value;
                var redirect = document.getElementById('setting_sc_redirect').value;
                var showPasswordLink = document.querySelector('input[name="setting_sc_show_password_link"]').checked;

                // Get defaults for current mode
                var currentDefaults = modeDefaults[mode] || modeDefaults.login;

                // Use mode-specific defaults if fields are empty
                var displayTitle = title || currentDefaults.title;
                var displayDesc = desc || currentDefaults.description;
                var displayButton = button || currentDefaults.button;

                var bgColor = document.getElementById('setting_style_bg_color').value;
                var borderColor = document.getElementById('setting_style_border_color').value;
                var borderRadius = document.getElementById('setting_style_border_radius').value;
                var titleColor = document.getElementById('setting_style_title_color').value;
                var descColor = document.getElementById('setting_style_desc_color').value;
                var inputBorderColor = document.getElementById('setting_style_input_border_color').value;
                var inputRadius = document.getElementById('setting_style_input_border_radius').value;
                var buttonBg = document.getElementById('setting_style_button_bg').value;
                var buttonTextColor = document.getElementById('setting_style_button_text_color').value;
                var buttonRadius = document.getElementById('setting_style_button_radius').value;

                // Update preview with display values (use mode defaults when empty)
                previewTitle.textContent = displayTitle;
                previewTitle.style.color = titleColor;
                previewDesc.textContent = displayDesc;
                previewDesc.style.color = descColor;
                previewInput.placeholder = placeholder || 'email@example.com';
                previewInput.style.borderColor = inputBorderColor;
                previewInput.style.borderRadius = inputRadius + 'px';
                previewButton.textContent = displayButton;
                previewButton.style.background = buttonBg;
                previewButton.style.color = buttonTextColor;
                previewButton.style.borderRadius = buttonRadius + 'px';
                previewContainer.style.background = bgColor;
                previewContainer.style.borderColor = borderColor;
                previewContainer.style.borderRadius = borderRadius + 'px';
                previewPasswordLink.style.display = showPasswordLink ? 'block' : 'none';
                previewPasswordLink.querySelector('a').style.color = descColor;

                // Update radius value displays
                document.querySelectorAll('input[type="range"].sml-builder-input').forEach(function(range) {
                    var valueDisplay = range.closest('div').querySelector('.sml-radius-value');
                    if (valueDisplay) valueDisplay.textContent = range.value + 'px';
                });

                // Generate shortcode - only include non-default attributes
                var shortcode = '[magic_login';
                // Mode: only include if not auto (auto is default)
                if (mode !== 'auto') shortcode += ' mode="' + mode + '"';
                // Title/Description/Button: only include if custom value provided
                if (title) shortcode += ' title="' + title + '"';
                if (desc) shortcode += ' description="' + desc + '"';
                if (button) shortcode += ' button="' + button + '"';
                if (redirect) shortcode += ' redirect="' + redirect + '"';
                if (!showPasswordLink) shortcode += ' show_password_link="no"';
                shortcode += ']';

                shortcodeOutput.textContent = shortcode;
            }

            // Color text sync
            document.querySelectorAll('.sml-color-text').forEach(function(input) {
                var colorInput = document.getElementById(input.dataset.for);

                input.addEventListener('input', function() {
                    if (/^#[0-9A-Fa-f]{6}$/.test(this.value)) {
                        colorInput.value = this.value;
                        updatePreview();
                    }
                });

                colorInput.addEventListener('input', function() {
                    input.value = this.value;
                });
            });

            // Bind all inputs
            document.querySelectorAll('.sml-builder-input').forEach(function(input) {
                input.addEventListener('input', updatePreview);
                input.addEventListener('change', updatePreview);
            });

            // Preset buttons
            document.querySelectorAll('.sml-preset-btn').forEach(function(btn) {
                btn.addEventListener('click', function() {
                    var containerRadius = parseInt(this.dataset.container);
                    var inputRadius = parseInt(this.dataset.input);
                    var buttonRadius = parseInt(this.dataset.button);

                    document.getElementById('setting_style_border_radius').value = containerRadius;
                    document.getElementById('setting_style_input_border_radius').value = inputRadius;
                    document.getElementById('setting_style_button_radius').value = buttonRadius;

                    updatePreview();
                });
            });

            // Copy shortcode
            document.getElementById('sml-copy-shortcode').addEventListener('click', function() {
                var btn = this;
                navigator.clipboard.writeText(shortcodeOutput.textContent).then(function() {
                    var originalText = btn.textContent;
                    btn.textContent = '<?php echo esc_js(__('Copied!', 'wpswitchboard')); ?>';
                    btn.style.background = '#16a34a';
                    setTimeout(function() {
                        btn.textContent = originalText;
                        btn.style.background = '#3b82f6';
                    }, 2000);
                });
            });

            // Mode-specific descriptions and registration notice
            var modeDescriptions = {
                auto: '<?php echo esc_js(__('Smart mode: if email exists → login, if new email → signup. Perfect for a unified login/register form.', 'wpswitchboard')); ?>',
                login: '<?php echo esc_js(__('Login-only mode: only existing users can sign in. New emails will see an error.', 'wpswitchboard')); ?>',
                register: '<?php echo esc_js(__('Signup-only mode: only new users can register. Existing users will see an error.', 'wpswitchboard')); ?>'
            };
            var modeSelect = document.getElementById('setting_sc_mode');
            var modeDescription = document.getElementById('sml-mode-description');
            var registrationNotice = document.getElementById('sml-mode-registration-notice');

            function updateModeUI() {
                var mode = modeSelect.value;

                // Update description
                if (modeDescription) {
                    modeDescription.textContent = modeDescriptions[mode] || modeDescriptions.login;
                }

                // Show/hide registration notice (only if WP registration is disabled)
                if (registrationNotice) {
                    var needsRegistration = (mode === 'auto' || mode === 'register');
                    registrationNotice.style.display = needsRegistration ? 'block' : 'none';
                }
            }

            modeSelect.addEventListener('change', function() {
                updateModeUI();
                updatePreview();
            });

            // Initial update
            updatePreview();
            updateModeUI();

            // Toggle placeholder info box visibility
            var autoLoginCheckbox = document.querySelector('input[name="setting_enable_auto_login"]');
            var placeholderInfo = document.getElementById('magic-link-placeholder-info');
            if (autoLoginCheckbox && placeholderInfo) {
                autoLoginCheckbox.addEventListener('change', function() {
                    placeholderInfo.style.display = this.checked ? 'block' : 'none';
                });
            }

            // Send Test Email button
            var testEmailBtn = document.getElementById('send-test-magic-email');
            var testEmailResult = document.getElementById('test-email-result');
            if (testEmailBtn) {
                testEmailBtn.addEventListener('click', function() {
                    testEmailBtn.disabled = true;
                    testEmailBtn.textContent = '<?php echo esc_js(__('Sending...', 'wpswitchboard')); ?>';
                    testEmailResult.textContent = '';
                    testEmailResult.style.color = '';

                    var formData = new FormData();
                    formData.append('action', 'switchboard_send_test_magic_email');
                    formData.append('nonce', '<?php echo wp_create_nonce('switchboard_test_magic_email'); ?>');

                    fetch(ajaxurl, {
                        method: 'POST',
                        body: formData
                    })
                    .then(function(response) { return response.json(); })
                    .then(function(data) {
                        if (data.success) {
                            testEmailResult.style.color = '#16a34a';
                            testEmailResult.textContent = data.data.message;
                        } else {
                            testEmailResult.style.color = '#dc2626';
                            testEmailResult.textContent = data.data.message || '<?php echo esc_js(__('Failed to send email.', 'wpswitchboard')); ?>';
                        }
                    })
                    .catch(function(error) {
                        testEmailResult.style.color = '#dc2626';
                        testEmailResult.textContent = '<?php echo esc_js(__('Network error. Please try again.', 'wpswitchboard')); ?>';
                    })
                    .finally(function() {
                        testEmailBtn.disabled = false;
                        testEmailBtn.textContent = '<?php echo esc_js(__('Send Test Email', 'wpswitchboard')); ?>';
                    });
                });
            }
        })();
        </script>

        <!-- Recent Activity -->
        <div class="sb-module-card sb-module-form-section">
            <div class="sb-module-card-header">
                <div class="sb-module-card-header-left">
                    <h2 class="sb-module-card-title"><?php _e('Recent Activity', 'wpswitchboard'); ?></h2>
                    <p class="sb-module-card-desc"><?php _e('Last 10 magic link requests', 'wpswitchboard'); ?></p>
                </div>
            </div>
            <div class="sb-module-card-body" style="padding: 0;">
                <?php if (empty($recent_links)): ?>
                    <div style="padding: 60px 20px; text-align: center;">
                        <div style="font-size: 48px; margin-bottom: 16px;"><span class="dashicons dashicons-star-filled" style="color: #f59e0b;"></span></div>
                        <p class="sb-sp-description" style="margin: 0; color: #64748b;"><?php _e('No magic links have been requested yet', 'wpswitchboard'); ?></p>
                        <p style="margin: 16px 0 0; color: #94a3b8; font-size: 13px;"><?php _e('Try logging out and using the magic link option on the login page!', 'wpswitchboard'); ?></p>
                    </div>
                <?php else: ?>
                    <div style="overflow-x: auto;">
                        <table class="widefat" style="margin: 0; border: 0; border-collapse: collapse; min-width: 700px;">
                            <thead>
                                <tr style="background: #f9fafb; border-bottom: 2px solid #e5e7eb;">
                                    <th style="padding: 12px 16px; text-align: left; font-size: 11px; font-weight: 600; color: #374151; text-transform: uppercase; letter-spacing: 0.5px;"><?php _e('User', 'wpswitchboard'); ?></th>
                                    <th style="padding: 12px 16px; text-align: left; font-size: 11px; font-weight: 600; color: #374151; text-transform: uppercase; letter-spacing: 0.5px;"><?php _e('Requested', 'wpswitchboard'); ?></th>
                                    <th style="padding: 12px 16px; text-align: left; font-size: 11px; font-weight: 600; color: #374151; text-transform: uppercase; letter-spacing: 0.5px;"><?php _e('Status', 'wpswitchboard'); ?></th>
                                    <th style="padding: 12px 16px; text-align: left; font-size: 11px; font-weight: 600; color: #374151; text-transform: uppercase; letter-spacing: 0.5px;"><?php _e('IP Address', 'wpswitchboard'); ?></th>
                                </tr>
                            </thead>
                            <tbody>
                                <?php foreach ($recent_links as $index => $link):
                                    $is_used = !empty($link->used_at);
                                    $expires_timestamp = $link->expires_at ? strtotime($link->expires_at . ' UTC') : 0;
                                    $is_expired = $expires_timestamp && $expires_timestamp < time();
                                    $is_even = ($index % 2 === 0);

                                    if ($is_used) {
                                        $status = 'used';
                                        $status_label = __('Used', 'wpswitchboard');
                                        $status_bg = '#dcfce7';
                                        $status_color = '#166534';
                                    } elseif ($is_expired) {
                                        $status = 'expired';
                                        $status_label = __('Expired', 'wpswitchboard');
                                        $status_bg = '#f3f4f6';
                                        $status_color = '#6b7280';
                                    } else {
                                        $status = 'pending';
                                        $status_label = __('Pending', 'wpswitchboard');
                                        $status_bg = '#fef3c7';
                                        $status_color = '#92400e';
                                    }
                                ?>
                                    <tr style="border-bottom: 1px solid #f3f4f6; background: <?php echo $is_even ? '#ffffff' : '#f9fafb'; ?>;">
                                        <td style="padding: 12px 16px;">
                                            <div style="display: flex; align-items: center; gap: 10px;">
                                                <?php echo get_avatar($link->user_id, 32, '', '', ['style' => 'border-radius: 50%;']); ?>
                                                <div>
                                                    <div style="font-weight: 500; color: #111827;"><?php echo esc_html($link->display_name); ?></div>
                                                    <div style="font-size: 12px; color: #64748b;"><?php echo esc_html($link->user_email); ?></div>
                                                </div>
                                            </div>
                                        </td>
                                        <td style="padding: 12px 16px; font-size: 13px; color: #64748b;">
                                            <?php
                                            $created_timestamp = strtotime($link->created_at);
                                            echo $created_timestamp ? human_time_diff($created_timestamp) . ' ago' : '—';
                                            ?>
                                        </td>
                                        <td style="padding: 12px 16px;">
                                            <span style="background: <?php echo $status_bg; ?>; color: <?php echo $status_color; ?>; padding: 3px 8px; border-radius: 4px; font-size: 11px; font-weight: 500;">
                                                <?php echo $status_label; ?>
                                            </span>
                                        </td>
                                        <td style="padding: 12px 16px; font-size: 12px; color: #64748b; font-family: 'SF Mono', Monaco, monospace;">
                                            <?php echo esc_html($link->ip_address ?: '—'); ?>
                                        </td>
                                    </tr>
                                <?php endforeach; ?>
                            </tbody>
                        </table>
                    </div>
                <?php endif; ?>
            </div>
        </div>

        <!-- Users Column Note -->
        <div class="sb-sp-info-box sb-sp-info-box-info" style="margin-top: 24px;">
            <h4 class="sb-sp-heading-sm"><?php _e('User List Column', 'wpswitchboard'); ?></h4>
            <p class="sb-sp-description" style="margin: 0;">
                <?php _e('A "Magic Login" column has been added to Users → All Users showing how many times each user has logged in via magic link and when they last used it.', 'wpswitchboard'); ?>
            </p>
        </div>
        <?php
    }
}

$switchboard_instance = new SwitchboardMagicLogin();
Switchboard_Data_Registry::get_instance()->auto_register($switchboard_instance, __FILE__);
