<?php
/**
 * Name: Simple CAPTCHA
 * Description: A self-hosted CAPTCHA solution that doesn't require external services. Supports math problems, text-based questions, and image CAPTCHAs. Perfect for privacy-conscious sites.
 * Category: Security
 * Icon: -
 * Version: 1.0
 * Database: no
 * UseCases: [
 *   {
 *     "title": "Login Protection",
 *     "description": "Add a simple math or text CAPTCHA to WordPress login form."
 *   },
 *   {
 *     "title": "Registration Protection",
 *     "description": "Prevent spam registrations with human verification."
 *   },
 *   {
 *     "title": "Comment Spam Prevention",
 *     "description": "Stop spam bots without requiring third-party services."
 *   },
 *   {
 *     "title": "Privacy-Focused Protection",
 *     "description": "Keep your site secure without sending data to Google or Cloudflare."
 *   }
 * ]
 * Added: 2025-01-07
 * Tags: captcha, math, spam, security, privacy, self-hosted, login, registration, comments
 * WhereToFind: {
 *   "location": "Module Settings",
 *   "instructions": "Configure CAPTCHA type and select which forms to protect."
 * }
 */

if (!defined('ABSPATH')) exit;

class SwitchboardSimpleCaptcha {

    private $option_key = 'switchboard_simple-captcha_settings';
    private $default_settings;
    private $transient_prefix = 'sb_captcha_';
    private $rate_limit_prefix = 'sb_captcha_rate_';
    private $rate_limit_max = 10; // Max refresh requests per minute
    private $rate_limit_window = 60; // Rate limit window in seconds

    public function __construct() {
        $this->default_settings = [
            'captcha_type' => 'math', // math, text, image
            'math_difficulty' => 'easy', // easy, medium, hard
            'text_questions' => [], // Custom text questions
            'image_style' => 'distorted', // distorted, simple
            'image_length' => 5, // Character length for image captcha
            'protect_login' => false,
            'protect_registration' => false,
            'protect_password_reset' => false,
            'protect_comments' => false,
            'protect_magic_login' => false,
            'protect_otp_login' => false,
            'protect_cf7' => false,
            'protect_fluent_forms' => false,
            'whitelist_logged_in' => true,
            'error_message' => 'CAPTCHA verification failed. Please try again.',
            'case_sensitive' => false, // For image captcha
        ];

        // Admin settings
        add_action('switchboard_module_settings_simple-captcha', [$this, 'render_settings']);

        $settings = $this->get_settings();

        // Login form protection
        if ($settings['protect_login']) {
            add_action('login_form', [$this, 'render_captcha']);
            add_action('login_footer', [$this, 'enqueue_styles_login']);
            add_filter('authenticate', [$this, 'verify_login'], 999, 3);
        }

        // Registration form protection
        if ($settings['protect_registration']) {
            add_action('register_form', [$this, 'render_captcha']);
            add_filter('registration_errors', [$this, 'verify_registration'], 10, 3);
        }

        // Password reset protection
        if ($settings['protect_password_reset']) {
            add_action('lostpassword_form', [$this, 'render_captcha']);
            add_action('lostpassword_post', [$this, 'verify_password_reset'], 10, 2);
        }

        // Comment form protection
        // Note: comment_form_after_fields fires for guest users, comment_form_logged_in_after for logged-in
        // We use render_captcha_for_comment to prevent double rendering
        if ($settings['protect_comments']) {
            add_action('comment_form_after_fields', [$this, 'render_captcha_for_comment']);
            add_action('comment_form_logged_in_after', [$this, 'render_captcha_for_comment']);
            add_filter('preprocess_comment', [$this, 'verify_comment']);
        }

        // Simple Forms integration (always enabled when CAPTCHA is configured)
        add_filter('switchboard_simple_form_validate', [$this, 'verify_simple_form'], 10, 2);
        add_action('switchboard_simple_form_after_fields', [$this, 'render_captcha_for_form']);

        // Magic Login integration hook
        if ($settings['protect_magic_login']) {
            add_filter('switchboard_magic_login_validate', [$this, 'verify_magic_login'], 10, 2);
            add_action('switchboard_magic_login_form_fields', [$this, 'render_captcha_for_form']);
        }

        // OTP Login integration hook
        if ($settings['protect_otp_login']) {
            add_filter('switchboard_otp_validate', [$this, 'verify_otp_login'], 10, 2);
            add_action('switchboard_otp_form_fields', [$this, 'render_captcha_for_form']);
        }

        // Contact Form 7 integration
        if (class_exists('WPCF7')) {
            // Always add tag generator in admin so users can add the tag before enabling protection
            if (is_admin()) {
                add_action('wpcf7_admin_init', [$this, 'cf7_add_tag_generator'], 60);
            }
            // Only add protection/validation hooks if enabled
            if ($settings['protect_cf7']) {
                $this->init_cf7_integration();
            }
        }

        // Fluent Forms integration
        if ($settings['protect_fluent_forms']) {
            $this->init_fluent_forms_integration();
        }

        // AJAX endpoint for image captcha
        add_action('wp_ajax_nopriv_switchboard_captcha_image', [$this, 'serve_captcha_image']);
        add_action('wp_ajax_switchboard_captcha_image', [$this, 'serve_captcha_image']);

        // AJAX endpoint to refresh captcha (generate new token and code)
        add_action('wp_ajax_nopriv_switchboard_captcha_refresh', [$this, 'ajax_refresh_captcha']);
        add_action('wp_ajax_switchboard_captcha_refresh', [$this, 'ajax_refresh_captcha']);

        // Frontend scripts (non-login pages)
        add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts_frontend']);

        // Provide filter for other modules
        add_filter('switchboard_simple_captcha_is_valid', [$this, 'check_captcha_response'], 10, 2);
    }

    /**
     * Get settings
     */
    public function get_settings() {
        $saved = get_option($this->option_key, []);
        $settings = wp_parse_args($saved, $this->default_settings);

        // Ensure text_questions is an array
        if (!is_array($settings['text_questions'])) {
            $settings['text_questions'] = [];
        }

        // Add default text questions if empty
        if (empty($settings['text_questions'])) {
            $settings['text_questions'] = $this->get_default_text_questions();
        }

        return $settings;
    }

    /**
     * Get default text questions
     */
    private function get_default_text_questions() {
        return [
            ['question' => 'What color is the sky on a clear day?', 'answers' => ['blue']],
            ['question' => 'What is the opposite of hot?', 'answers' => ['cold']],
            ['question' => 'How many days are in a week?', 'answers' => ['7', 'seven']],
            ['question' => 'What animal says "meow"?', 'answers' => ['cat', 'cats', 'a cat']],
            ['question' => 'What comes after Monday?', 'answers' => ['tuesday']],
            ['question' => 'What season comes after winter?', 'answers' => ['spring']],
            ['question' => 'What is 2 + 2?', 'answers' => ['4', 'four']],
            ['question' => 'What planet do we live on?', 'answers' => ['earth']],
        ];
    }

    /**
     * Generate a unique captcha token
     */
    private function generate_token() {
        return wp_generate_password(32, false);
    }

    /**
     * Store captcha answer in transient
     * Extended to 15 minutes to handle slow form submissions
     */
    private function store_answer($token, $answer) {
        set_transient($this->transient_prefix . $token, $answer, 15 * MINUTE_IN_SECONDS);
    }

    /**
     * Verify captcha answer with improved security
     */
    private function verify_answer($token, $answer) {
        // Basic validation
        if (empty($token) || empty($answer)) {
            return false;
        }

        // Validate token format (32 alphanumeric characters)
        if (strlen($token) !== 32 || !ctype_alnum($token)) {
            return false;
        }

        // Sanitize answer - limit length to prevent abuse
        $answer = substr(trim($answer), 0, 100);

        $stored_answer = get_transient($this->transient_prefix . $token);

        if ($stored_answer === false) {
            return false;
        }

        // Delete transient after use (one-time use) - prevents replay attacks
        delete_transient($this->transient_prefix . $token);

        $settings = $this->get_settings();

        // Compare answers based on captcha type
        if (is_array($stored_answer)) {
            // Text questions - check if answer matches any valid answer
            $answer = strtolower(trim($answer));
            foreach ($stored_answer as $valid) {
                if (strtolower(trim($valid)) === $answer) {
                    return true;
                }
            }
            return false;
        }

        // For image captcha
        if ($settings['captcha_type'] === 'image') {
            if ($settings['case_sensitive']) {
                return trim($answer) === trim($stored_answer);
            }
            return strtolower(trim($answer)) === strtolower(trim($stored_answer));
        }

        // For math captcha - compare as strings
        return trim($answer) === trim($stored_answer);
    }

    /**
     * Generate math problem
     */
    private function generate_math_problem() {
        $settings = $this->get_settings();
        $difficulty = $settings['math_difficulty'];

        switch ($difficulty) {
            case 'hard':
                // Two operations or larger numbers
                $ops = ['+', '-', '*'];
                $op1 = $ops[wp_rand(0, count($ops) - 1)];
                $op2 = $ops[wp_rand(0, count($ops) - 1)];
                $a = wp_rand(5, 20);
                $b = wp_rand(2, 10);
                $c = wp_rand(1, 5);

                // Ensure no negative results for subtraction
                if ($op1 === '-' && $b > $a) {
                    $temp = $a;
                    $a = $b;
                    $b = $temp;
                }

                $intermediate = $this->calculate($a, $b, $op1);

                if ($op2 === '-' && $c > $intermediate) {
                    $op2 = '+';
                }

                $answer = $this->calculate($intermediate, $c, $op2);
                $question = "$a $op1 $b $op2 $c";
                break;

            case 'medium':
                // Single operation, larger numbers or multiplication
                $ops = ['+', '-', '*'];
                $op = $ops[wp_rand(0, count($ops) - 1)];

                if ($op === '*') {
                    $a = wp_rand(2, 9);
                    $b = wp_rand(2, 9);
                } else {
                    $a = wp_rand(10, 30);
                    $b = wp_rand(5, 15);
                }

                // Ensure no negative results
                if ($op === '-' && $b > $a) {
                    $temp = $a;
                    $a = $b;
                    $b = $temp;
                }

                $answer = $this->calculate($a, $b, $op);
                $question = "$a $op $b";
                break;

            case 'easy':
            default:
                // Simple addition/subtraction with small numbers
                $ops = ['+', '-'];
                $op = $ops[wp_rand(0, count($ops) - 1)];
                $a = wp_rand(1, 10);
                $b = wp_rand(1, 10);

                // Ensure no negative results
                if ($op === '-' && $b > $a) {
                    $temp = $a;
                    $a = $b;
                    $b = $temp;
                }

                $answer = $this->calculate($a, $b, $op);
                $question = "$a $op $b";
                break;
        }

        return [
            'question' => $question,
            'answer' => (string) $answer,
        ];
    }

    /**
     * Calculate math operation
     */
    private function calculate($a, $b, $op) {
        switch ($op) {
            case '+':
                return $a + $b;
            case '-':
                return $a - $b;
            case '*':
                return $a * $b;
            default:
                return $a + $b;
        }
    }

    /**
     * Generate text question
     */
    private function generate_text_question() {
        $settings = $this->get_settings();
        $questions = $settings['text_questions'];

        if (empty($questions)) {
            $questions = $this->get_default_text_questions();
        }

        $selected = $questions[wp_rand(0, count($questions) - 1)];

        return [
            'question' => $selected['question'],
            'answer' => $selected['answers'],
        ];
    }

    /**
     * Generate image captcha code
     */
    private function generate_image_code() {
        $settings = $this->get_settings();
        $length = $settings['image_length'];

        // Use characters that are less ambiguous
        $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
        $code = '';

        for ($i = 0; $i < $length; $i++) {
            $code .= $chars[wp_rand(0, strlen($chars) - 1)];
        }

        return $code;
    }

    /**
     * Render captcha widget
     */
    public function render_captcha() {
        // Check if another CAPTCHA module already rendered
        global $switchboard_captcha_rendered;
        if (!empty($switchboard_captcha_rendered)) {
            return;
        }
        $switchboard_captcha_rendered = 'simple_captcha';

        $settings = $this->get_settings();

        // Skip for logged-in users if whitelist enabled
        if ($settings['whitelist_logged_in'] && is_user_logged_in()) {
            return;
        }

        $token = $this->generate_token();
        $captcha_type = $settings['captcha_type'];

        // Fallback to math captcha if image is selected but GD is not available
        if ($captcha_type === 'image' && !$this->is_gd_available()) {
            $captcha_type = 'math';
            // Log this for admin awareness
            if (current_user_can('manage_options')) {
                error_log('Switchboard Simple CAPTCHA: GD library not available, falling back to math captcha');
            }
        }

        switch ($captcha_type) {
            case 'text':
                $data = $this->generate_text_question();
                $this->store_answer($token, $data['answer']);
                $this->render_text_captcha($token, $data['question']);
                break;

            case 'image':
                $code = $this->generate_image_code();
                $this->store_answer($token, $code);
                $this->render_image_captcha($token);
                break;

            case 'math':
            default:
                $data = $this->generate_math_problem();
                $this->store_answer($token, $data['answer']);
                $this->render_math_captcha($token, $data['question']);
                break;
        }
    }

    /**
     * Render captcha for comment form (prevents double rendering)
     * Both comment_form_after_fields and comment_form_logged_in_after can fire on the same page
     */
    public function render_captcha_for_comment() {
        static $comment_captcha_rendered = false;

        if ($comment_captcha_rendered) {
            return;
        }
        $comment_captcha_rendered = true;

        $this->render_captcha();
    }

    /**
     * Render math captcha
     */
    private function render_math_captcha($token, $question) {
        ?>
        <div class="switchboard-captcha switchboard-captcha-math" style="margin: 15px 0;">
            <label class="switchboard-captcha-label" style="display: block; margin-bottom: 8px; font-weight: 500;">
                What is <?php echo esc_html($question); ?>?
            </label>
            <input type="hidden" name="switchboard_captcha_token" value="<?php echo esc_attr($token); ?>">
            <input type="text"
                   name="switchboard_captcha_answer"
                   class="switchboard-captcha-input"
                   placeholder="Enter your answer"
                   required
                   autocomplete="off"
                   style="width: 100%; max-width: 200px; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px;">
        </div>
        <?php
    }

    /**
     * Render text captcha
     */
    private function render_text_captcha($token, $question) {
        ?>
        <div class="switchboard-captcha switchboard-captcha-text" style="margin: 15px 0;">
            <label class="switchboard-captcha-label" style="display: block; margin-bottom: 8px; font-weight: 500;">
                <?php echo esc_html($question); ?>
            </label>
            <input type="hidden" name="switchboard_captcha_token" value="<?php echo esc_attr($token); ?>">
            <input type="text"
                   name="switchboard_captcha_answer"
                   class="switchboard-captcha-input"
                   placeholder="Enter your answer"
                   required
                   autocomplete="off"
                   style="width: 100%; max-width: 300px; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px;">
        </div>
        <?php
    }

    /**
     * Render image captcha
     */
    private function render_image_captcha($token) {
        $image_url = admin_url('admin-ajax.php?action=switchboard_captcha_image&token=' . urlencode($token) . '&t=' . time());
        $nonce = wp_create_nonce('switchboard_captcha_refresh');
        $refresh_url = admin_url('admin-ajax.php?action=switchboard_captcha_refresh&type=image&_wpnonce=' . $nonce);
        $captcha_id = 'sb-captcha-' . wp_rand(1000, 9999);
        ?>
        <style>
        .switchboard-captcha-image .switchboard-captcha-img-wrapper {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            gap: 8px;
            margin-bottom: 8px;
        }
        @media (max-width: 480px) {
            .switchboard-captcha-image .switchboard-captcha-img-wrapper {
                flex-direction: column;
                align-items: flex-start;
            }
            .switchboard-captcha-image .switchboard-captcha-refresh {
                margin-left: 0 !important;
            }
        }
        </style>
        <div class="switchboard-captcha switchboard-captcha-image" id="<?php echo esc_attr($captcha_id); ?>" style="margin: 15px 0;">
            <label class="switchboard-captcha-label" style="display: block; margin-bottom: 8px; font-weight: 500;">
                <?php esc_html_e('Enter the characters shown below:', 'wpswitchboard'); ?>
            </label>
            <div class="switchboard-captcha-img-wrapper">
                <img src="<?php echo esc_url($image_url); ?>"
                     alt="CAPTCHA"
                     class="switchboard-captcha-image-display"
                     style="border: 1px solid #d1d5db; border-radius: 6px; height: 50px; max-width: 100%;">
                <button type="button"
                        class="switchboard-captcha-refresh"
                        data-refresh-url="<?php echo esc_url($refresh_url); ?>"
                        data-captcha-id="<?php echo esc_attr($captcha_id); ?>"
                        style="padding: 8px 12px; background: #f3f4f6; border: 1px solid #d1d5db; border-radius: 6px; cursor: pointer; font-size: 14px; white-space: nowrap;">
                    <?php esc_html_e('Refresh', 'wpswitchboard'); ?>
                </button>
            </div>
            <input type="hidden" name="switchboard_captcha_token" value="<?php echo esc_attr($token); ?>" class="switchboard-captcha-token">
            <input type="text"
                   name="switchboard_captcha_answer"
                   class="switchboard-captcha-input"
                   placeholder="<?php esc_attr_e('Enter characters', 'wpswitchboard'); ?>"
                   required
                   autocomplete="off"
                   style="width: 100%; max-width: 200px; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; text-transform: uppercase;">
            <div class="switchboard-captcha-error" style="display: none; color: #dc2626; font-size: 13px; margin-top: 4px;"></div>
        </div>
        <script>
        (function() {
            var container = document.getElementById('<?php echo esc_js($captcha_id); ?>');
            if (!container) return;
            var btn = container.querySelector('.switchboard-captcha-refresh');
            var errorEl = container.querySelector('.switchboard-captcha-error');
            if (!btn) return;

            function showError(msg) {
                if (errorEl) {
                    errorEl.textContent = msg;
                    errorEl.style.display = 'block';
                    setTimeout(function() { errorEl.style.display = 'none'; }, 5000);
                }
            }

            btn.addEventListener('click', function() {
                var url = this.getAttribute('data-refresh-url');
                // Include old token for cleanup
                var oldToken = container.querySelector('.switchboard-captcha-token').value;
                if (oldToken) {
                    url += '&old_token=' + encodeURIComponent(oldToken);
                }
                btn.disabled = true;
                btn.innerHTML = '⟳ ...';
                if (errorEl) errorEl.style.display = 'none';

                // Create abort controller for timeout
                var controller = new AbortController();
                var timeoutId = setTimeout(function() { controller.abort(); }, 15000);

                fetch(url, { signal: controller.signal })
                    .then(function(r) {
                        clearTimeout(timeoutId);
                        if (!r.ok) {
                            if (r.status === 429) {
                                throw new Error('<?php echo esc_js(__('Too many requests. Please wait.', 'wpswitchboard')); ?>');
                            }
                            throw new Error('<?php echo esc_js(__('Request failed. Please try again.', 'wpswitchboard')); ?>');
                        }
                        return r.json();
                    })
                    .then(function(data) {
                        if (data.success && data.data) {
                            container.querySelector('.switchboard-captcha-image-display').src = data.data.image_url;
                            container.querySelector('.switchboard-captcha-token').value = data.data.token;
                            container.querySelector('.switchboard-captcha-input').value = '';
                            // Update nonce for subsequent refreshes
                            if (data.data.nonce) {
                                var currentUrl = btn.getAttribute('data-refresh-url');
                                var newUrl = currentUrl.replace(/_wpnonce=[^&]+/, '_wpnonce=' + data.data.nonce);
                                btn.setAttribute('data-refresh-url', newUrl);
                            }
                        } else {
                            showError(data.data && data.data.message ? data.data.message : '<?php echo esc_js(__('Failed to refresh. Please reload the page.', 'wpswitchboard')); ?>');
                        }
                        btn.disabled = false;
                        btn.innerHTML = '<?php echo esc_js(__('Refresh', 'wpswitchboard')); ?>';
                    })
                    .catch(function(err) {
                        clearTimeout(timeoutId);
                        btn.disabled = false;
                        btn.innerHTML = '<?php echo esc_js(__('Refresh', 'wpswitchboard')); ?>';
                        if (err.name === 'AbortError') {
                            showError('<?php echo esc_js(__('Request timed out. Please try again.', 'wpswitchboard')); ?>');
                        } else {
                            showError(err.message || '<?php echo esc_js(__('Network error. Please try again.', 'wpswitchboard')); ?>');
                        }
                    });
            });
        })();
        </script>
        <?php
    }

    /**
     * Check rate limiting for captcha refresh
     * Uses atomic increment pattern to prevent race conditions
     */
    private function check_rate_limit() {
        $ip = $this->get_client_ip();
        $rate_key = $this->rate_limit_prefix . md5($ip);

        // Use wp_cache for atomic operations if available (object cache)
        // Fall back to transient with lock for file/db based caching
        $lock_key = $rate_key . '_lock';
        $lock_timeout = 5; // 5 second lock timeout

        // Try to acquire lock to prevent race condition
        $lock_acquired = false;
        $attempts = 0;
        while (!$lock_acquired && $attempts < 10) {
            $lock_value = get_transient($lock_key);
            if ($lock_value === false) {
                set_transient($lock_key, time(), $lock_timeout);
                $lock_acquired = true;
            } else {
                // Lock exists - check if it's stale
                if (time() - intval($lock_value) > $lock_timeout) {
                    // Stale lock, take over
                    set_transient($lock_key, time(), $lock_timeout);
                    $lock_acquired = true;
                } else {
                    // Wait briefly and retry
                    usleep(50000); // 50ms
                    $attempts++;
                }
            }
        }

        if (!$lock_acquired) {
            // Could not acquire lock, fail safe by allowing request
            return true;
        }

        $current_count = get_transient($rate_key);

        if ($current_count === false) {
            set_transient($rate_key, 1, $this->rate_limit_window);
            delete_transient($lock_key);
            return true;
        }

        if ($current_count >= $this->rate_limit_max) {
            delete_transient($lock_key);
            return false;
        }

        set_transient($rate_key, $current_count + 1, $this->rate_limit_window);
        delete_transient($lock_key);
        return true;
    }

    /**
     * Get client IP address with Cloudflare support
     */
    private function get_client_ip() {
        $ip = '';

        // Check for Cloudflare
        if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
            $ip = sanitize_text_field(wp_unslash($_SERVER['HTTP_CF_CONNECTING_IP']));
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            // X-Forwarded-For can contain multiple IPs, take the first one
            $ips = explode(',', sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR'])));
            $ip = trim($ips[0]);
        } elseif (!empty($_SERVER['HTTP_X_REAL_IP'])) {
            $ip = sanitize_text_field(wp_unslash($_SERVER['HTTP_X_REAL_IP']));
        } elseif (!empty($_SERVER['REMOTE_ADDR'])) {
            $ip = sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR']));
        }

        // Validate IP
        if (filter_var($ip, FILTER_VALIDATE_IP)) {
            return $ip;
        }

        return '0.0.0.0';
    }

    /**
     * Check if GD library is available for image captcha
     */
    private function is_gd_available() {
        return extension_loaded('gd') && function_exists('imagecreatetruecolor');
    }

    /**
     * AJAX handler to refresh captcha (generates new token and code)
     */
    public function ajax_refresh_captcha() {
        // Verify nonce for CSRF protection
        if (!isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'switchboard_captcha_refresh')) {
            wp_send_json_error([
                'message' => __('Security check failed. Please reload the page.', 'wpswitchboard'),
                'code' => 'nonce_failed'
            ], 403);
        }

        // Rate limiting check
        if (!$this->check_rate_limit()) {
            wp_send_json_error([
                'message' => __('Too many requests. Please wait before refreshing again.', 'wpswitchboard'),
                'code' => 'rate_limited'
            ], 429);
        }

        $type = isset($_GET['type']) ? sanitize_text_field(wp_unslash($_GET['type'])) : 'image';
        $settings = $this->get_settings();

        // Validate captcha type
        if (!in_array($type, ['math', 'text', 'image'], true)) {
            wp_send_json_error(['message' => __('Invalid CAPTCHA type', 'wpswitchboard')]);
        }

        // Generate new token
        $token = $this->generate_token();

        // Generate a new nonce for subsequent refreshes
        $new_nonce = wp_create_nonce('switchboard_captcha_refresh');

        // Clean up old token if provided (prevents orphan transients)
        $old_token = isset($_GET['old_token']) ? sanitize_text_field(wp_unslash($_GET['old_token'])) : '';
        if (!empty($old_token) && strlen($old_token) === 32 && ctype_alnum($old_token)) {
            delete_transient($this->transient_prefix . $old_token);
        }

        if ($type === 'image') {
            $code = $this->generate_image_code();
            $this->store_answer($token, $code);
            $image_url = admin_url('admin-ajax.php?action=switchboard_captcha_image&token=' . urlencode($token) . '&t=' . time());

            wp_send_json_success([
                'token' => $token,
                'image_url' => $image_url,
                'nonce' => $new_nonce,
            ]);
        } elseif ($type === 'math') {
            $data = $this->generate_math_problem();
            $this->store_answer($token, $data['answer']);

            wp_send_json_success([
                'token' => $token,
                'question' => $data['question'],
                'nonce' => $new_nonce,
            ]);
        } elseif ($type === 'text') {
            $data = $this->generate_text_question();
            $this->store_answer($token, $data['answer']);

            wp_send_json_success([
                'token' => $token,
                'question' => $data['question'],
                'nonce' => $new_nonce,
            ]);
        }

        // This line is unreachable due to validation on line 711, but kept for safety
        wp_send_json_error(['message' => 'Invalid CAPTCHA type']);
    }

    /**
     * Serve captcha image
     */
    public function serve_captcha_image() {
        // Check if GD library is available
        if (!$this->is_gd_available()) {
            // Serve a simple text-based fallback image
            header('Content-Type: text/plain');
            wp_die('Image CAPTCHA requires GD library. Please contact your hosting provider or use Math/Text CAPTCHA instead.');
        }

        // Rate limiting for image requests
        if (!$this->check_rate_limit()) {
            header('HTTP/1.1 429 Too Many Requests');
            header('Retry-After: 60');
            wp_die('Too many requests. Please wait before trying again.');
        }

        $token = isset($_GET['token']) ? sanitize_text_field(wp_unslash($_GET['token'])) : '';

        // Validate token format (should be 32 characters alphanumeric)
        if (empty($token) || strlen($token) !== 32 || !ctype_alnum($token)) {
            wp_die('Invalid request');
        }

        // Get stored answer
        $code = get_transient($this->transient_prefix . $token);

        if ($code === false) {
            wp_die('CAPTCHA expired. Please refresh the page.');
        }

        // If code is an array (text question answers), don't serve image
        if (is_array($code)) {
            wp_die('Invalid CAPTCHA type');
        }

        // Validate code format (should be uppercase alphanumeric)
        if (!preg_match('/^[A-Z0-9]+$/', $code)) {
            wp_die('Invalid CAPTCHA data');
        }

        $settings = $this->get_settings();

        // Generate image
        $this->generate_captcha_image($code, $settings['image_style']);
        exit;
    }

    /**
     * Generate captcha image
     */
    private function generate_captcha_image($code, $style = 'distorted') {
        // Image dimensions
        $width = 150;
        $height = 50;

        // Create image
        $image = imagecreatetruecolor($width, $height);

        // Handle image creation failure
        if ($image === false) {
            header('Content-Type: text/plain');
            header('HTTP/1.1 500 Internal Server Error');
            wp_die('Failed to create CAPTCHA image. Please try Math or Text CAPTCHA instead.');
        }

        // Colors
        $bg_color = imagecolorallocate($image, 255, 255, 255);
        $text_color = imagecolorallocate($image, 50, 50, 50);
        $noise_color = imagecolorallocate($image, 150, 150, 150);
        $line_color = imagecolorallocate($image, 200, 200, 200);

        // Fill background
        imagefill($image, 0, 0, $bg_color);

        if ($style === 'distorted') {
            // Add noise lines
            for ($i = 0; $i < 5; $i++) {
                imageline($image, wp_rand(0, $width), wp_rand(0, $height), wp_rand(0, $width), wp_rand(0, $height), $line_color);
            }

            // Add noise dots
            for ($i = 0; $i < 100; $i++) {
                imagesetpixel($image, wp_rand(0, $width), wp_rand(0, $height), $noise_color);
            }
        }

        // Add text
        $font_size = 5; // Built-in font size (1-5)
        $char_width = imagefontwidth($font_size);
        $char_height = imagefontheight($font_size);

        $text_width = strlen($code) * $char_width;
        $x = ($width - $text_width) / 2;
        $y = ($height - $char_height) / 2;

        if ($style === 'distorted') {
            // Draw each character with slight random offset
            for ($i = 0; $i < strlen($code); $i++) {
                $char_x = $x + ($i * $char_width) + wp_rand(-2, 2);
                $char_y = $y + wp_rand(-3, 3);
                imagestring($image, $font_size, $char_x, $char_y, $code[$i], $text_color);
            }
        } else {
            // Simple style - just draw the text
            imagestring($image, $font_size, $x, $y, $code, $text_color);
        }

        // Output image
        header('Content-Type: image/png');
        header('Cache-Control: no-cache, no-store, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');

        imagepng($image);
        imagedestroy($image);
    }

    /**
     * Render captcha for form (with form context)
     * This bypasses duplicate prevention since Magic Login etc. are separate forms
     */
    public function render_captcha_for_form($form_id = null) {
        // Check if another CAPTCHA module already rendered for THIS form
        global $switchboard_captcha_rendered_form;
        $form_key = $form_id ?: 'default';
        if (!empty($switchboard_captcha_rendered_form[$form_key])) {
            return;
        }
        $switchboard_captcha_rendered_form[$form_key] = 'simple_captcha';

        $settings = $this->get_settings();

        // Skip for logged-in users if whitelist enabled
        if ($settings['whitelist_logged_in'] && is_user_logged_in()) {
            return;
        }

        $token = $this->generate_token();
        $captcha_type = $settings['captcha_type'];

        // Fallback to math captcha if image is selected but GD is not available
        if ($captcha_type === 'image' && !$this->is_gd_available()) {
            $captcha_type = 'math';
        }

        switch ($captcha_type) {
            case 'text':
                $data = $this->generate_text_question();
                $this->store_answer($token, $data['answer']);
                $this->render_text_captcha($token, $data['question']);
                break;

            case 'image':
                $code = $this->generate_image_code();
                $this->store_answer($token, $code);
                $this->render_image_captcha($token);
                break;

            case 'math':
            default:
                $data = $this->generate_math_problem();
                $this->store_answer($token, $data['answer']);
                $this->render_math_captcha($token, $data['question']);
                break;
        }
    }

    /**
     * Enqueue styles on login page
     */
    public function enqueue_styles_login() {
        ?>
        <style>
        .switchboard-captcha { margin: 15px 0; }
        .switchboard-captcha-label { display: block; margin-bottom: 8px; font-weight: 500; }
        .switchboard-captcha-input { width: 100%; max-width: 200px; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; }
        </style>
        <?php
    }

    /**
     * Enqueue scripts on frontend
     */
    public function enqueue_scripts_frontend() {
        $settings = $this->get_settings();

        // Only enqueue if needed on this page
        // Simple Forms protection is always enabled when module is active
        $needs_script = $settings['protect_comments']
            || $settings['protect_magic_login']
            || $settings['protect_otp_login']
            || $settings['protect_cf7']
            || $settings['protect_fluent_forms']
            || class_exists('SwitchboardSimpleForms');

        if (!$needs_script) {
            return;
        }

        wp_add_inline_style('wp-block-library', '
            .switchboard-captcha { margin: 15px 0; }
            .switchboard-captcha-label { display: block; margin-bottom: 8px; font-weight: 500; }
            .switchboard-captcha-input { width: 100%; max-width: 200px; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; }
        ');
    }

    /**
     * Verify captcha response
     * Returns true if valid, false if invalid
     */
    private function verify_response() {
        $settings = $this->get_settings();

        // Skip for logged-in users if enabled
        if ($settings['whitelist_logged_in'] && is_user_logged_in()) {
            return true;
        }

        // Check if captcha fields exist in POST
        if (!isset($_POST['switchboard_captcha_token']) || !isset($_POST['switchboard_captcha_answer'])) {
            // Captcha fields missing - could be form submitted without captcha rendered
            return false;
        }

        $token = sanitize_text_field(wp_unslash($_POST['switchboard_captcha_token']));
        $answer = sanitize_text_field(wp_unslash($_POST['switchboard_captcha_answer']));

        // Empty answer check
        if (empty($answer)) {
            return false;
        }

        return $this->verify_answer($token, $answer);
    }

    /**
     * Check if another CAPTCHA module is handling this form
     * Skip validation if another CAPTCHA's response is present
     */
    private function another_captcha_is_active() {
        // Check if Turnstile response is present (Cloudflare Turnstile is active)
        if (!empty($_POST['cf-turnstile-response'])) {
            return true;
        }
        // Check if reCAPTCHA response is present (Google reCAPTCHA is active)
        if (!empty($_POST['g-recaptcha-response'])) {
            return true;
        }
        return false;
    }

    /**
     * Verify login
     */
    public function verify_login($user, $username, $password) {
        // If already an error, return it (another plugin already rejected)
        if (is_wp_error($user)) {
            return $user;
        }

        // Don't check captcha if no credentials provided
        if (empty($username) || empty($password)) {
            return $user;
        }

        // Skip if another CAPTCHA module is handling this form
        if ($this->another_captcha_is_active()) {
            return $user;
        }

        if (!$this->verify_response()) {
            return new WP_Error('captcha_failed', '<strong>' . esc_html__('Error', 'wpswitchboard') . ':</strong> ' . esc_html($this->get_settings()['error_message']));
        }

        return $user;
    }

    /**
     * Verify registration
     */
    public function verify_registration($errors, $sanitized_user_login, $user_email) {
        // Skip if another CAPTCHA module is handling this form
        if ($this->another_captcha_is_active()) {
            return $errors;
        }
        if (!$this->verify_response()) {
            $errors->add('captcha_failed', $this->get_settings()['error_message']);
        }
        return $errors;
    }

    /**
     * Verify password reset
     * Uses static flag to prevent double-validation when both WP and WooCommerce hooks fire
     */
    public function verify_password_reset($errors, $user_data) {
        static $password_reset_validated = false;

        if ($password_reset_validated) {
            return;
        }
        $password_reset_validated = true;

        // Skip if another CAPTCHA module is handling this form
        if ($this->another_captcha_is_active()) {
            return;
        }

        if (!$this->verify_response()) {
            $errors->add('captcha_failed', $this->get_settings()['error_message']);
        }
    }

    /**
     * Verify comment
     */
    public function verify_comment($commentdata) {
        // Skip captcha check for logged-in users if whitelist is enabled
        // Also handles admin/editor users submitting comments
        $settings = $this->get_settings();
        if ($settings['whitelist_logged_in'] && is_user_logged_in()) {
            return $commentdata;
        }

        // Skip if another CAPTCHA module is handling this form
        if ($this->another_captcha_is_active()) {
            return $commentdata;
        }

        if (!$this->verify_response()) {
            wp_die(
                '<p><strong>' . esc_html__('Error', 'wpswitchboard') . ':</strong> ' . esc_html($settings['error_message']) . '</p>',
                esc_html__('CAPTCHA Failed', 'wpswitchboard'),
                ['back_link' => true, 'response' => 403]
            );
        }
        return $commentdata;
    }

    /**
     * Check if Simple CAPTCHA was responsible for rendering
     */
    private function should_validate_captcha($form_id = null) {
        global $switchboard_captcha_rendered;

        // No flag set - we should validate (backwards compat)
        if (empty($switchboard_captcha_rendered)) {
            return true;
        }

        // Check if simple_captcha was the one that rendered
        return $switchboard_captcha_rendered === 'simple_captcha';
    }

    /**
     * Verify Simple Form submission
     * Only validates if this module rendered the CAPTCHA
     */
    public function verify_simple_form($valid, $form_id) {
        // Only validate if Simple CAPTCHA was the one that rendered
        if (!$this->should_validate_captcha($form_id)) {
            return $valid;
        }
        if (!$this->verify_response()) {
            return new WP_Error('captcha_failed', $this->get_settings()['error_message']);
        }
        return $valid;
    }

    /**
     * Verify Magic Login submission
     * Only validates if this module rendered the CAPTCHA
     */
    public function verify_magic_login($valid, $email) {
        // Only validate if Simple CAPTCHA was the one that rendered
        if (!$this->should_validate_captcha()) {
            return $valid;
        }
        // Skip if another CAPTCHA module is handling this form
        if ($this->another_captcha_is_active()) {
            return $valid;
        }
        if (!$this->verify_response()) {
            return new WP_Error('captcha_failed', $this->get_settings()['error_message']);
        }
        return $valid;
    }

    /**
     * Verify OTP Login submission
     * Only validates if this module rendered the CAPTCHA
     */
    public function verify_otp_login($valid, $user_id) {
        // Only validate if Simple CAPTCHA was the one that rendered
        if (!$this->should_validate_captcha()) {
            return $valid;
        }
        // Skip if another CAPTCHA module is handling this form
        if ($this->another_captcha_is_active()) {
            return $valid;
        }
        if (!$this->verify_response()) {
            return new WP_Error('captcha_failed', $this->get_settings()['error_message']);
        }
        return $valid;
    }

    // =========================================================================
    // Contact Form 7 Integration
    // =========================================================================

    /**
     * Initialize Contact Form 7 integration
     * Registers [switchboard_captcha] form tag for CF7
     */
    private function init_cf7_integration() {
        // CF7's wpcf7_init fires on 'init' priority 10
        // Switchboard also loads modules on 'init' priority 10
        // If wpcf7_add_form_tag exists, wpcf7_init has already fired - register immediately
        // Otherwise, hook into wpcf7_init for later registration
        if (function_exists('wpcf7_add_form_tag')) {
            $this->cf7_add_form_tag();
        }
        // Also add the hook in case wpcf7_init fires later (e.g., different load order)
        add_action('wpcf7_init', [$this, 'cf7_add_form_tag'], 1);

        // Validate submission - use wpcf7_validate filter with our tag
        add_filter('wpcf7_validate_switchboard_captcha', [$this, 'cf7_validate_tag'], 10, 2);
        add_filter('wpcf7_validate_switchboard_captcha*', [$this, 'cf7_validate_tag'], 10, 2);

        // Enqueue scripts on pages with CF7 forms
        add_action('wpcf7_enqueue_scripts', [$this, 'enqueue_scripts_frontend']);

        // Tag generator button is added in constructor (unconditionally in admin)
    }

    /**
     * Register CF7 form tag
     * Users add [switchboard_captcha] to their form
     */
    public function cf7_add_form_tag() {
        static $registered = false;

        if ($registered || !function_exists('wpcf7_add_form_tag')) {
            return;
        }
        $registered = true;

        wpcf7_add_form_tag(
            ['switchboard_captcha', 'switchboard_captcha*'],
            [$this, 'cf7_render_tag'],
            ['name-attr' => true]
        );
    }

    /**
     * Render CF7 form tag
     */
    public function cf7_render_tag($tag) {
        $settings = $this->get_settings();

        if ($settings['whitelist_logged_in'] && is_user_logged_in()) {
            return '';
        }

        $validation_error = wpcf7_get_validation_error($tag->name);

        ob_start();
        echo '<span class="wpcf7-form-control-wrap" data-name="' . esc_attr($tag->name) . '">';
        $this->render_captcha();
        echo wp_kses_post($validation_error);
        echo '</span>';
        return ob_get_clean();
    }

    /**
     * Validate CF7 form tag
     */
    public function cf7_validate_tag($result, $tag) {
        $settings = $this->get_settings();

        // Skip for logged-in users if whitelist enabled
        if ($settings['whitelist_logged_in'] && is_user_logged_in()) {
            return $result;
        }

        if (!$this->verify_response()) {
            $result->invalidate($tag, $settings['error_message']);
        }

        return $result;
    }

    /**
     * Add tag generator button in CF7 form editor
     */
    public function cf7_add_tag_generator() {
        if (!function_exists('wpcf7_add_tag_generator')) {
            return;
        }

        wpcf7_add_tag_generator(
            'switchboard_captcha',
            __('Simple CAPTCHA', 'wpswitchboard'),
            'wpcf7-tg-pane-switchboard-captcha',
            [$this, 'cf7_tag_generator_panel']
        );
    }

    /**
     * Render tag generator panel in CF7 form editor
     */
    public function cf7_tag_generator_panel($contact_form, $args = '') {
        $args = wp_parse_args($args, []);
        $type = 'switchboard_captcha';
        ?>
        <div class="control-box">
            <fieldset>
                <legend><?php esc_html_e('Generate a Simple CAPTCHA tag', 'wpswitchboard'); ?></legend>
                <table class="form-table">
                    <tbody>
                        <tr>
                            <th scope="row">
                                <label for="<?php echo esc_attr($args['content'] . '-required'); ?>">
                                    <?php esc_html_e('Required field', 'wpswitchboard'); ?>
                                </label>
                            </th>
                            <td>
                                <input type="checkbox" name="required" id="<?php echo esc_attr($args['content'] . '-required'); ?>" checked="checked" />
                            </td>
                        </tr>
                        <tr>
                            <th scope="row">
                                <label for="<?php echo esc_attr($args['content'] . '-name'); ?>">
                                    <?php esc_html_e('Name', 'wpswitchboard'); ?>
                                </label>
                            </th>
                            <td>
                                <input type="text" name="name" class="tg-name oneline" id="<?php echo esc_attr($args['content'] . '-name'); ?>" value="captcha" />
                            </td>
                        </tr>
                    </tbody>
                </table>
            </fieldset>
        </div>
        <div class="insert-box">
            <input type="text" name="<?php echo esc_attr($type); ?>" class="tag code" readonly="readonly" onfocus="this.select()" />
            <div class="submitbox">
                <input type="button" class="button button-primary insert-tag" value="<?php esc_attr_e('Insert Tag', 'wpswitchboard'); ?>" />
            </div>
            <br class="clear" />
            <p class="description mail-tag">
                <label>
                    <?php esc_html_e('This field does not need to be included in the mail template.', 'wpswitchboard'); ?>
                </label>
            </p>
        </div>
        <?php
    }

    // =========================================================================
    // Fluent Forms Integration
    // =========================================================================

    /**
     * Initialize Fluent Forms integration
     * Registers a custom field type using BaseFieldManager
     */
    private function init_fluent_forms_integration() {
        // Only initialize if Fluent Forms is active
        if (!class_exists('FluentForm\App\Services\FormBuilder\BaseFieldManager')) {
            return;
        }
        // Initialize the Fluent Forms field manager
        new SwitchboardFluentFormsCaptcha($this);
    }

    /**
     * Filter for other modules to check captcha
     */
    public function check_captcha_response($valid, $token = null) {
        return $this->verify_response();
    }

    /**
     * Render settings page
     */
    public function render_settings() {
        $settings = $this->get_settings();
        $questions = !empty($settings['text_questions']) ? $settings['text_questions'] : $this->get_default_text_questions();
        ?>
        <div class="sb-module-settings-form">
            <input type="hidden" name="module" value="simple-captcha">

            <!-- Info Box -->
            <div class="sb-sp-alert sb-sp-alert-info">
                <div class="sb-sp-alert-title">Self-Hosted CAPTCHA</div>
                <div class="sb-sp-alert-text">This CAPTCHA solution runs entirely on your server. No data is sent to external services like Google or Cloudflare, making it perfect for privacy-conscious websites.</div>
            </div>

            <?php
            // Check for other active CAPTCHA modules
            $other_captchas = [];
            if (class_exists('SwitchboardCloudflareTurnstile')) {
                $turnstile_settings = get_option('switchboard_cloudflare-turnstile_settings', []);
                if (!empty($turnstile_settings['site_key']) && !empty($turnstile_settings['secret_key'])) {
                    $other_captchas[] = 'Cloudflare Turnstile';
                }
            }
            if (class_exists('SwitchboardGoogleReCaptcha')) {
                $recaptcha_settings = get_option('switchboard_google-recaptcha_settings', []);
                if (!empty($recaptcha_settings['site_key']) && !empty($recaptcha_settings['secret_key'])) {
                    $other_captchas[] = 'Google reCAPTCHA';
                }
            }
            if (!empty($other_captchas)): ?>
            <div class="sb-sp-alert sb-sp-alert-warning" style="margin-bottom: 16px;">
                <div class="sb-sp-alert-title"><?php esc_html_e('Other CAPTCHA Module Active', 'wpswitchboard'); ?></div>
                <div class="sb-sp-alert-text">
                    <?php echo esc_html(implode(' and ', $other_captchas)); ?> <?php echo count($other_captchas) > 1 ? esc_html__('are', 'wpswitchboard') : esc_html__('is', 'wpswitchboard'); ?> <?php esc_html_e('also enabled. Only one CAPTCHA will be shown per form - enabling multiple CAPTCHA modules is unnecessary and may cause conflicts. We recommend using only one CAPTCHA solution.', 'wpswitchboard'); ?>
                </div>
            </div>
            <?php endif; ?>

            <!-- CAPTCHA Type -->
            <h3 class="sb-sp-heading">CAPTCHA Type</h3>
            <p class="sb-sp-description" style="margin-bottom: 16px;">Choose the type of challenge visitors must complete</p>

            <div class="sb-sp-radio-cards" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 24px;">
                <label class="sb-sp-radio-card" style="display: block; padding: 16px; background: #fff; border: 2px solid var(--gray-200, #e5e7eb); border-radius: 12px; cursor: pointer; transition: all 0.2s ease; position: relative;">
                    <input type="radio" name="captcha_type" value="math" <?php checked($settings['captcha_type'], 'math'); ?> style="position: absolute; top: 16px; right: 16px; width: 18px; height: 18px; accent-color: var(--primary-500, #3b82f6);">
                    <div style="padding-right: 30px;">
                        <div style="font-weight: bold; font-size: 18px; margin-bottom: 8px;">123</div>
                        <div style="font-weight: 600; color: var(--gray-900, #111827); margin-bottom: 4px;">Math Problem</div>
                        <div style="font-size: 13px; color: var(--gray-500, #6b7280);">e.g., "What is 5 + 3?"</div>
                    </div>
                </label>

                <label class="sb-sp-radio-card" style="display: block; padding: 16px; background: #fff; border: 2px solid var(--gray-200, #e5e7eb); border-radius: 12px; cursor: pointer; transition: all 0.2s ease; position: relative;">
                    <input type="radio" name="captcha_type" value="text" <?php checked($settings['captcha_type'], 'text'); ?> style="position: absolute; top: 16px; right: 16px; width: 18px; height: 18px; accent-color: var(--primary-500, #3b82f6);">
                    <div style="padding-right: 30px;">
                        <div style="font-weight: bold; font-size: 18px; margin-bottom: 8px;">Q&amp;A</div>
                        <div style="font-weight: 600; color: var(--gray-900, #111827); margin-bottom: 4px;">Text Question</div>
                        <div style="font-size: 13px; color: var(--gray-500, #6b7280);">e.g., "What color is the sky?"</div>
                    </div>
                </label>

                <label class="sb-sp-radio-card" style="display: block; padding: 16px; background: #fff; border: 2px solid var(--gray-200, #e5e7eb); border-radius: 12px; cursor: pointer; transition: all 0.2s ease; position: relative;">
                    <input type="radio" name="captcha_type" value="image" <?php checked($settings['captcha_type'], 'image'); ?> style="position: absolute; top: 16px; right: 16px; width: 18px; height: 18px; accent-color: var(--primary-500, #3b82f6);">
                    <div style="padding-right: 30px;">
                        <div style="font-weight: bold; font-size: 18px; margin-bottom: 8px;">IMG</div>
                        <div style="font-weight: 600; color: var(--gray-900, #111827); margin-bottom: 4px;">Image CAPTCHA</div>
                        <div style="font-size: 13px; color: var(--gray-500, #6b7280);">Traditional distorted text image</div>
                    </div>
                </label>
            </div>

            <div class="sb-sp-divider"></div>

            <!-- Math Options -->
            <div id="math_options" style="<?php echo $settings['captcha_type'] !== 'math' ? 'display:none;' : ''; ?>">
                <div class="sb-sp-group sb-sp-field-horizontal" style="margin-bottom: 24px;">
                    <div class="sb-sp-field-horizontal-left">
                        <label for="math_difficulty" class="sb-sp-label"><?php esc_html_e('Math Difficulty', 'wpswitchboard'); ?></label>
                        <p class="sb-sp-description"><?php esc_html_e('How difficult should the math problems be?', 'wpswitchboard'); ?></p>
                    </div>
                    <select name="math_difficulty" id="math_difficulty" class="sb-sp-select">
                        <option value="easy" <?php selected($settings['math_difficulty'], 'easy'); ?>>Easy (e.g., 5 + 3)</option>
                        <option value="medium" <?php selected($settings['math_difficulty'], 'medium'); ?>>Medium (e.g., 15 + 8 or 6 × 7)</option>
                        <option value="hard" <?php selected($settings['math_difficulty'], 'hard'); ?>>Hard (e.g., 12 + 5 - 3)</option>
                    </select>
                </div>
                <div class="sb-sp-divider"></div>
            </div>

            <!-- Text Options -->
            <div id="text_options" style="<?php echo $settings['captcha_type'] !== 'text' ? 'display:none;' : ''; ?>">
                <div class="sb-sp-group" style="margin-bottom: 24px;">
                    <h3 class="sb-sp-heading">Text Question Settings</h3>
                    <p class="sb-sp-description" style="margin-bottom: 16px;">Customize the questions asked. Each question can have multiple valid answers (comma-separated).</p>

                    <div id="text_questions_container">
                        <?php foreach ($questions as $index => $q): ?>
                        <div class="text-question-row" style="display: flex; gap: 12px; margin-bottom: 12px; align-items: flex-start;">
                            <div style="flex: 2;">
                                <input type="text"
                                       name="text_questions[<?php echo esc_attr($index); ?>][question]"
                                       value="<?php echo esc_attr($q['question']); ?>"
                                       class="sb-sp-input"
                                       placeholder="Question"
                                       style="width: 100%;">
                            </div>
                            <div style="flex: 1;">
                                <input type="text"
                                       name="text_questions[<?php echo esc_attr($index); ?>][answers]"
                                       value="<?php echo esc_attr(implode(', ', (array)$q['answers'])); ?>"
                                       class="sb-sp-input"
                                       placeholder="Answers (comma-separated)"
                                       style="width: 100%;">
                            </div>
                            <button type="button" onclick="this.parentElement.remove();" class="button" style="color: #dc2626;">×</button>
                        </div>
                        <?php endforeach; ?>
                    </div>

                    <button type="button" id="add_question_btn" class="button">+ Add Question</button>
                </div>
                <div class="sb-sp-divider"></div>
            </div>

            <!-- Image Options -->
            <div id="image_options" style="<?php echo $settings['captcha_type'] !== 'image' ? 'display:none;' : ''; ?>">
                <?php if (!$this->is_gd_available()): ?>
                <div class="sb-sp-alert sb-sp-alert-warning" style="margin-bottom: 16px;">
                    <div class="sb-sp-alert-title">GD Library Not Available</div>
                    <div class="sb-sp-alert-text">The GD library is required for Image CAPTCHA but is not installed on your server. Image CAPTCHA will automatically fall back to Math CAPTCHA. Contact your hosting provider to enable the GD extension.</div>
                </div>
                <?php endif; ?>
                <div class="sb-sp-group sb-sp-field-horizontal" style="margin-bottom: 24px;">
                    <div class="sb-sp-field-horizontal-left">
                        <label for="image_style" class="sb-sp-label"><?php esc_html_e('Image Style', 'wpswitchboard'); ?></label>
                        <p class="sb-sp-description"><?php esc_html_e('How distorted should the text appear?', 'wpswitchboard'); ?></p>
                    </div>
                    <select name="image_style" id="image_style" class="sb-sp-select">
                        <option value="distorted" <?php selected($settings['image_style'], 'distorted'); ?>>Distorted (harder)</option>
                        <option value="simple" <?php selected($settings['image_style'], 'simple'); ?>>Simple (easier)</option>
                    </select>
                </div>

                <div class="sb-sp-group sb-sp-field-horizontal" style="margin-bottom: 24px;">
                    <div class="sb-sp-field-horizontal-left">
                        <label for="image_length" class="sb-sp-label"><?php esc_html_e('Character Length', 'wpswitchboard'); ?></label>
                        <p class="sb-sp-description"><?php esc_html_e('Number of characters to display', 'wpswitchboard'); ?></p>
                    </div>
                    <select name="image_length" id="image_length" class="sb-sp-select">
                        <option value="4" <?php selected($settings['image_length'], 4); ?>>4 characters</option>
                        <option value="5" <?php selected($settings['image_length'], 5); ?>>5 characters</option>
                        <option value="6" <?php selected($settings['image_length'], 6); ?>>6 characters</option>
                    </select>
                </div>

                <div class="sb-module-option-item sb-module-toggle-item">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <strong class="sb-module-option-title"><?php esc_html_e('Case Sensitive', 'wpswitchboard'); ?></strong>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="case_sensitive" value="1" <?php checked($settings['case_sensitive']); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                        <p class="sb-module-option-text"><?php esc_html_e('Require exact case matching (makes CAPTCHA harder)', 'wpswitchboard'); ?></p>
                    </div>
                </div>
                <div class="sb-sp-divider"></div>
            </div>

            <!-- Form Protection -->
            <h3 class="sb-sp-heading">Form Protection</h3>
            <p class="sb-sp-description" style="margin-bottom: 16px;">Select which forms to protect with Simple CAPTCHA</p>

            <div class="sb-sp-checkbox-grid" style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;">
                <div class="sb-module-option-item sb-module-toggle-item">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <div class="sb-module-option-info">
                                <strong class="sb-module-option-title">WordPress Login</strong>
                                <p class="sb-module-option-text">Add CAPTCHA to wp-login.php</p>
                            </div>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="protect_login" value="1" <?php checked($settings['protect_login']); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                    </div>
                </div>

                <div class="sb-module-option-item sb-module-toggle-item">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <div class="sb-module-option-info">
                                <strong class="sb-module-option-title">Registration Form</strong>
                                <p class="sb-module-option-text">Prevent spam registrations</p>
                            </div>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="protect_registration" value="1" <?php checked($settings['protect_registration']); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                    </div>
                </div>

                <div class="sb-module-option-item sb-module-toggle-item">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <div class="sb-module-option-info">
                                <strong class="sb-module-option-title">Password Reset</strong>
                                <p class="sb-module-option-text">Protect lost password requests</p>
                            </div>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="protect_password_reset" value="1" <?php checked($settings['protect_password_reset']); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                    </div>
                </div>

                <div class="sb-module-option-item sb-module-toggle-item">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <div class="sb-module-option-info">
                                <strong class="sb-module-option-title">Comment Form</strong>
                                <p class="sb-module-option-text">Stop spam comments on posts</p>
                            </div>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="protect_comments" value="1" <?php checked($settings['protect_comments']); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                    </div>
                </div>

                <div class="sb-module-option-item sb-module-toggle-item">
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <div class="sb-module-option-info">
                                <strong class="sb-module-option-title">Magic Login</strong>
                                <p class="sb-module-option-text">Protect passwordless login</p>
                            </div>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="protect_magic_login" value="1" <?php checked($settings['protect_magic_login']); ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                    </div>
                </div>

                <?php $otp_active = class_exists('SwitchboardOtpLogin'); ?>
                <div class="sb-module-option-item sb-module-toggle-item" <?php echo !$otp_active ? 'style="opacity: 0.5;"' : ''; ?>>
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <div class="sb-module-option-info">
                                <strong class="sb-module-option-title">OTP Login</strong>
                                <p class="sb-module-option-text"><?php echo $otp_active ? 'Protect OTP verification' : 'Module not active'; ?></p>
                            </div>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="protect_otp_login" value="1" <?php checked($settings['protect_otp_login']); ?> <?php echo !$otp_active ? 'disabled' : ''; ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Third-Party Integrations -->
            <h4 class="sb-sp-heading-sm" style="margin-top: 24px;">Third-Party Integrations</h4>
            <p class="sb-sp-description" style="margin-bottom: 12px;">Enable to add a "Simple CAPTCHA" field type in each form builder</p>
            <div class="sb-sp-checkbox-grid" style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-top: 12px;">
                <?php $cf7_installed = defined('WPCF7_VERSION'); ?>
                <div class="sb-module-option-item sb-module-toggle-item" <?php echo !$cf7_installed ? 'style="opacity: 0.5;"' : ''; ?>>
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <div class="sb-module-option-info">
                                <strong class="sb-module-option-title">Contact Form 7</strong>
                                <p class="sb-module-option-text"><?php echo $cf7_installed ? 'Adds [switchboard_captcha] tag' : 'Not installed'; ?></p>
                            </div>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="protect_cf7" value="1" <?php checked($settings['protect_cf7']); ?> <?php echo !$cf7_installed ? 'disabled' : ''; ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                    </div>
                </div>

                <?php $ff_installed = defined('FLUENTFORM_VERSION') || defined('FLUENTFORM'); ?>
                <div class="sb-module-option-item sb-module-toggle-item" <?php echo !$ff_installed ? 'style="opacity: 0.5;"' : ''; ?>>
                    <div class="sb-module-option-content">
                        <div class="sb-module-toggle-header">
                            <div class="sb-module-option-info">
                                <strong class="sb-module-option-title">Fluent Forms</strong>
                                <p class="sb-module-option-text"><?php echo $ff_installed ? 'Adds "Simple CAPTCHA" in Advanced fields' : 'Not installed'; ?></p>
                            </div>
                            <label class="sb-module-toggle">
                                <input type="checkbox" name="protect_fluent_forms" value="1" <?php checked($settings['protect_fluent_forms']); ?> <?php echo !$ff_installed ? 'disabled' : ''; ?>>
                                <span class="sb-module-toggle-slider"></span>
                            </label>
                        </div>
                    </div>
                </div>
            </div>

            <div class="sb-sp-divider"></div>

            <!-- Options -->
            <h3 class="sb-sp-heading">Options</h3>

            <div class="sb-module-option-item sb-module-toggle-item">
                <div class="sb-module-option-content">
                    <div class="sb-module-toggle-header">
                        <strong class="sb-module-option-title"><?php esc_html_e('Skip for Logged-in Users', 'wpswitchboard'); ?></strong>
                        <label class="sb-module-toggle">
                            <input type="checkbox" name="whitelist_logged_in" value="1" <?php checked($settings['whitelist_logged_in']); ?>>
                            <span class="sb-module-toggle-slider"></span>
                        </label>
                    </div>
                    <p class="sb-module-option-text"><?php esc_html_e('Logged-in users will not see CAPTCHA challenges', 'wpswitchboard'); ?></p>
                </div>
            </div>

            <div class="sb-sp-group sb-sp-field-horizontal" style="margin-top: 24px; margin-bottom: 24px;">
                <div class="sb-sp-field-horizontal-left">
                    <label for="error_message" class="sb-sp-label"><?php esc_html_e('Error Message', 'wpswitchboard'); ?></label>
                    <p class="sb-sp-description"><?php esc_html_e('Message shown when CAPTCHA verification fails', 'wpswitchboard'); ?></p>
                </div>
                <input type="text" name="error_message" id="error_message" value="<?php echo esc_attr($settings['error_message']); ?>" class="sb-sp-input">
            </div>

            <div class="sb-sp-divider"></div>

            <!-- Tip Box -->
            <div class="sb-sp-card sb-sp-p-4">
                <h4 class="sb-sp-heading-sm sb-sp-mb-3">Tips</h4>
                <ul class="sb-sp-list">
                    <li class="sb-sp-list-item"><strong>Math CAPTCHA:</strong> Best balance of security and usability</li>
                    <li class="sb-sp-list-item"><strong>Text Questions:</strong> Create custom questions only you know the answers to</li>
                    <li class="sb-sp-list-item"><strong>Image CAPTCHA:</strong> Traditional approach, works without JavaScript</li>
                    <li class="sb-sp-list-item"><strong>Privacy:</strong> All verification happens on your server - no third-party tracking</li>
                </ul>
            </div>
        </div>

        <script>
        (function() {
            // Toggle options based on captcha type
            document.querySelectorAll('input[name="captcha_type"]').forEach(function(radio) {
                radio.addEventListener('change', function() {
                    document.getElementById('math_options').style.display = this.value === 'math' ? 'block' : 'none';
                    document.getElementById('text_options').style.display = this.value === 'text' ? 'block' : 'none';
                    document.getElementById('image_options').style.display = this.value === 'image' ? 'block' : 'none';
                });
            });

            // Add question button
            var questionIndex = <?php echo count($questions); ?>;
            document.getElementById('add_question_btn').addEventListener('click', function() {
                var container = document.getElementById('text_questions_container');
                var row = document.createElement('div');
                row.className = 'text-question-row';
                row.style.cssText = 'display: flex; gap: 12px; margin-bottom: 12px; align-items: flex-start;';
                row.innerHTML = '<div style="flex: 2;"><input type="text" name="text_questions[' + questionIndex + '][question]" class="sb-sp-input" placeholder="Question" style="width: 100%;"></div><div style="flex: 1;"><input type="text" name="text_questions[' + questionIndex + '][answers]" class="sb-sp-input" placeholder="Answers (comma-separated)" style="width: 100%;"></div><button type="button" onclick="this.parentElement.remove();" class="button" style="color: #dc2626;">×</button>';
                container.appendChild(row);
                questionIndex++;
            });
        })();
        </script>
        <?php
    }

}

/**
 * Fluent Forms Custom Field - Simple CAPTCHA
 * Extends BaseFieldManager to register a proper custom field type
 */
if (class_exists('FluentForm\App\Services\FormBuilder\BaseFieldManager')) {
    class SwitchboardFluentFormsCaptcha extends \FluentForm\App\Services\FormBuilder\BaseFieldManager
    {
        private $captcha_module;

        public function __construct($captcha_module)
        {
            $this->captcha_module = $captcha_module;

            parent::__construct(
                'switchboard_simple_captcha',           // key
                __('Simple CAPTCHA', 'wpswitchboard'), // title
                ['captcha', 'security', 'spam'],        // tags
                'advanced'                              // section
            );

            // Add validation filter
            add_filter('fluentform/validate_input_item_switchboard_simple_captcha', [$this, 'validate'], 10, 5);

            // Hide field from entries (captcha answers shouldn't be stored)
            $this->hideFieldFromEntries();
        }

        /**
         * Get component definition for form builder
         */
        public function getComponent()
        {
            return [
                'index'          => 20,
                'element'        => $this->key,
                'attributes'     => [
                    'name'  => $this->key,
                    'class' => '',
                    'value' => '',
                    'type'  => 'text',
                ],
                'settings'       => [
                    'container_class'    => '',
                    'label'              => __('Security Check', 'wpswitchboard'),
                    'label_placement'    => '',
                    'help_message'       => '',
                    'error_message'      => __('CAPTCHA verification failed. Please try again.', 'wpswitchboard'),
                    'conditional_logics' => [],
                ],
                'editor_options' => [
                    'title'      => __('Simple CAPTCHA', 'wpswitchboard'),
                    'icon_class' => 'ff-edit-shield',
                    'template'   => 'inputText',
                ],
            ];
        }

        /**
         * Define which settings appear in General tab
         */
        public function getGeneralEditorElements()
        {
            return [
                'label',
                'label_placement',
            ];
        }

        /**
         * Define custom editor elements
         */
        public function generalEditorElement()
        {
            return [
                'error_message' => [
                    'template' => 'inputText',
                    'label'    => __('Error Message', 'wpswitchboard'),
                ],
                'help_message' => [
                    'template' => 'inputText',
                    'label'    => __('Help Text', 'wpswitchboard'),
                ],
            ];
        }

        /**
         * Render the captcha field on frontend
         * Note: We echo the captcha directly and return empty string because
         * render_captcha() already outputs a complete UI with input field.
         * Returning anything would cause Fluent Forms to render additional elements.
         */
        public function render($data, $form)
        {
            $settings = $this->captcha_module->get_settings();

            // Skip for logged-in users if whitelist enabled
            if ($settings['whitelist_logged_in'] && is_user_logged_in()) {
                return '';
            }

            // render_captcha() outputs the complete captcha UI including:
            // - The visual challenge (image, math question, or text question)
            // - Hidden token field
            // - Input field for answer
            // - Refresh button (for image captcha)
            $this->captcha_module->render_captcha();

            // Return empty string - our captcha already has its own input field
            // Don't let BaseFieldManager render additional elements
            return '';
        }

        /**
         * Validate the captcha on form submission
         */
        public function validate($errorMessage, $field, $formData, $fields, $form)
        {
            $settings = $this->captcha_module->get_settings();

            // Skip for logged-in users if whitelist enabled
            if ($settings['whitelist_logged_in'] && is_user_logged_in()) {
                return $errorMessage;
            }

            // Get token and answer from POST
            $token = isset($_POST['switchboard_captcha_token']) ? sanitize_text_field(wp_unslash($_POST['switchboard_captcha_token'])) : '';
            $answer = isset($_POST['switchboard_captcha_answer']) ? sanitize_text_field(wp_unslash($_POST['switchboard_captcha_answer'])) : '';

            // Check if captcha verification passes
            if (empty($token) || empty($answer)) {
                $error_msg = isset($field['raw']['settings']['error_message']) ? $field['raw']['settings']['error_message'] : $settings['error_message'];
                return [$error_msg];
            }

            // Use reflection to access private verify_answer method, or add a public wrapper
            // For now, we'll directly check the transient
            $transient_prefix = 'sb_captcha_';
            $stored_answer = get_transient($transient_prefix . $token);

            if ($stored_answer === false) {
                $error_msg = isset($field['raw']['settings']['error_message']) ? $field['raw']['settings']['error_message'] : $settings['error_message'];
                return [$error_msg];
            }

            // Delete transient after use (one-time use)
            delete_transient($transient_prefix . $token);

            // Compare answers
            $is_valid = false;
            if (is_array($stored_answer)) {
                // Text questions - check if answer matches any valid answer
                $answer_lower = strtolower(trim($answer));
                foreach ($stored_answer as $valid) {
                    if (strtolower(trim($valid)) === $answer_lower) {
                        $is_valid = true;
                        break;
                    }
                }
            } elseif ($settings['captcha_type'] === 'image') {
                // Image captcha
                if ($settings['case_sensitive']) {
                    $is_valid = trim($answer) === trim($stored_answer);
                } else {
                    $is_valid = strtolower(trim($answer)) === strtolower(trim($stored_answer));
                }
            } else {
                // Math captcha
                $is_valid = trim($answer) === trim($stored_answer);
            }

            if (!$is_valid) {
                $error_msg = isset($field['raw']['settings']['error_message']) ? $field['raw']['settings']['error_message'] : $settings['error_message'];
                return [$error_msg];
            }

            return $errorMessage;
        }

        /**
         * Hide captcha field from form entries
         */
        private function hideFieldFromEntries()
        {
            add_filter('fluentform/all_entry_labels', function ($formLabels, $form_id) {
                if (!function_exists('wpFluent')) {
                    return $formLabels;
                }
                $form = wpFluent()->table('fluentform_forms')->find($form_id);
                if (!$form) {
                    return $formLabels;
                }
                $fields = \FluentForm\App\Modules\Form\FormFieldsParser::getInputsByElementTypes($form, [$this->key]);
                if (is_array($fields) && !empty($fields)) {
                    foreach (array_keys($fields) as $key) {
                        unset($formLabels[$key]);
                    }
                }
                return $formLabels;
            }, 10, 2);
        }
    }
}

new SwitchboardSimpleCaptcha();
