<?php
declare(strict_types=1);

namespace WPUltimateSecurity\UltimateSecurity\Modules\Protection;

use WPUltimateSecurity\UltimateSecurity\Support\Helpers\Utils;
use WPUltimateSecurity\UltimateSecurity\Support\Helpers\IpHelper;
use WPUltimateSecurity\UltimateSecurity\Modules\TestMode\TestModeService;
use WPUltimateSecurity\UltimateSecurity\Modules\Base\AbstractModule;
use WP_Error;

class GoogleRecaptcha extends AbstractModule
{
    /**
     * Module identifier.
     */
    public const MODULE_ID = 'protection.recaptcha';

    /**
     * Module version.
     */
    protected const VERSION = '2.0.0';

    /**
     * Get the unique module identifier.
     *
     * @return string
     */
    public static function getId(): string
    {
        return self::MODULE_ID;
    }

    /**
     * Get the human-readable module name.
     *
     * @return string
     */
    public static function getName(): string
    {
        return __('Google reCAPTCHA', 'ultimate-security');
    }

    /**
     * Get the module domain.
     *
     * @return string
     */
    public static function getDomain(): string
    {
        return 'protection';
    }

    /**
     * Boot the module (registers hooks and handlers).
     *
     * @return void
     */
    public static function boot(): void
    {
        $ultimate_security_options = Utils::ultimate_security_get_option();
        // security[re_captcha][enable]
        $security_re_captcha_enable = isset($ultimate_security_options['security']['re_captcha']['enable']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['enable'])) : 0;
        // security[re_captcha][no_conflict_mode]
        $security_re_captcha_no_conflict_mode = isset($ultimate_security_options['security']['re_captcha']['no_conflict_mode']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['no_conflict_mode'])) : 0;
        $ultimate_security_disable_recaptcha_script = 0;
        if ($security_re_captcha_enable && $security_re_captcha_no_conflict_mode) {
            add_action('login_head', [self::class, 'disable_recaptcha_script']);
            add_action('wp', [self::class, 'disable_recaptcha_script_woo']);
            $ultimate_security_disable_recaptcha_script = get_option('ultimate_security_disable_recaptcha_script', 0);
        }

        if ($security_re_captcha_enable && !$ultimate_security_disable_recaptcha_script) {
            // Check if Turnstile is enabled for login - if so, skip reCAPTCHA on login to avoid dual CAPTCHA
            $turnstile_enabled_for_login = isset($ultimate_security_options['security']['cloudflare_turnstile']['wordpress_login'])
                && $ultimate_security_options['security']['cloudflare_turnstile']['wordpress_login'];

            add_action('login_enqueue_scripts', [self::class, 'enqueue_recaptcha_script']);
            add_action('wp_enqueue_scripts', [self::class, 'enqueue_recaptcha_script']);

            add_action('login_head', [self::class, 'custom_login_inline_scripts']);

            // Only add reCAPTCHA to login form if Turnstile is not enabled (mutual exclusion)
            if (!$turnstile_enabled_for_login) {
                add_action('login_form', [self::class, 'add_recaptcha_to_form'], 999999);
            }
            add_action('register_form', [self::class, 'add_recaptcha_to_form'], 999999);
            add_action('lostpassword_form', [self::class, 'add_recaptcha_to_form'], 999999);
            // security[re_captcha][enable_woocommerce]
            $security_re_captcha_enable_woocommerce = isset($ultimate_security_options['security']['re_captcha']['enable_woocommerce']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['enable_woocommerce'])) : 0;
            if ($security_re_captcha_enable_woocommerce) {
                add_action('woocommerce_login_form', [self::class, 'add_recaptcha_to_form'], 999999);
                add_action('woocommerce_register_form', [self::class, 'add_recaptcha_to_form'], 999999);
                add_action('woocommerce_process_login_errors', [self::class, 'verify_recaptcha_on_woocommerce_login'], 10, 2);
                add_action('woocommerce_register_post', [self::class, 'verify_recaptcha_on_woocommerce_register'], 10, 3);
                add_action('woocommerce_before_checkout_form', [self::class, 'enqueue_recaptcha_script']);
                add_action('woocommerce_before_customer_login_form', [self::class, 'enqueue_recaptcha_script']);
                add_action('woocommerce_before_register_form', [self::class, 'enqueue_recaptcha_script']);
            }

            add_action('wp_authenticate_user', [self::class, 'verify_recaptcha_response'], 10, 2);
            add_action('register_post', [self::class, 'verify_recaptcha_on_registration'], 10, 3);
            add_action('lostpassword_post', [self::class, 'verify_recaptcha_on_lostpassword']);
        }
    }

    public static function enqueue_recaptcha_script()
    {
        $ultimate_security_options = Utils::ultimate_security_get_option();
        //security[re_captcha][site_key]
        $site_key = isset($ultimate_security_options['security']['re_captcha']['site_key']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['site_key'])) : '';
        //security[re_captcha][type]
        $captcha_version = isset($ultimate_security_options['security']['re_captcha']['type']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['type'])) : 'v2';

        if (!$site_key) {
            return;
        }

        if ($captcha_version === 'v2') {
            wp_enqueue_script('ultimate-security-google-recaptcha', 'https://www.google.com/recaptcha/api.js', [], null, true);
        } elseif ($captcha_version === 'v3') {
            wp_enqueue_script('ultimate-security-google-recaptcha', 'https://www.google.com/recaptcha/api.js?render=' . esc_attr($site_key), [], null, true);

        }
    }
    public static function disable_recaptcha_script()
    {
        global $wp_scripts;
        $ultimate_security_options = Utils::ultimate_security_get_option();
        $already_installed = 0;
        foreach ($wp_scripts->registered as $handle => $script) {
            if (is_string($script->src) && preg_match('/recaptcha/i', $script->src) && $handle !== 'ultimate-security-google-recaptcha') {
                $already_installed++;
            }
        }

        // Update the option to store the number of reCAPTCHA scripts found.
        update_option('ultimate_security_disable_recaptcha_script', $already_installed);

        $recaptcha_checked = 0;
        if (isset($_GET['_wpnonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'ultimate-security-login')) {
            $recaptcha_checked = isset($_GET['recaptcha_checked']) ? sanitize_text_field(wp_unslash($_GET['recaptcha_checked'])) : 0;
        }

        // Check if this is the first redirect by looking for a custom query parameter.
        if ($already_installed && !$recaptcha_checked) {
            $security_login_security_custom_login_url = isset($ultimate_security_options['security']['login_security']['custom_login_url']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['login_security']['custom_login_url'])) : '/wp-login.php';
            // Add a query parameter to indicate the check has already been performed.
            $redirect_url = add_query_arg('recaptcha_checked', '1', home_url($security_login_security_custom_login_url)) . '&_wpnonce=' . wp_create_nonce('ultimate-security-login');
            wp_safe_redirect($redirect_url);
            exit;
        }
    }
    public static function disable_recaptcha_script_woo()
    {
        $ultimate_security_options = Utils::ultimate_security_get_option();
        if (get_option('woocommerce_myaccount_page_id') == get_the_ID() && !is_user_logged_in()) {
            $security_login_security_custom_login_url = isset($ultimate_security_options['security']['login_security']['custom_login_url']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['login_security']['custom_login_url'])) : '/wp-login.php';
            wp_safe_redirect(home_url($security_login_security_custom_login_url));
            exit;
        }
    }
    public static function add_recaptcha_to_form()
    {
        $ultimate_security_options = Utils::ultimate_security_get_option();
        // security[re_captcha][site_key]
        $site_key = isset($ultimate_security_options['security']['re_captcha']['site_key']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['site_key'])) : '';
        // security[re_captcha][type]
        $captcha_version = isset($ultimate_security_options['security']['re_captcha']['type']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['type'])) : 'v2';
        // security[re_captcha][theme]
        $theme = isset($ultimate_security_options['security']['re_captcha']['theme']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['theme'])) : 'light';
        // security[re_captcha][size]
        $size = isset($ultimate_security_options['security']['re_captcha']['size']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['size'])) : 'normal';

        if (!$site_key) {
            return;
        }
        wp_nonce_field('ultimate_security_login_nonce_action', 'ultimate_security_login_nonce_field', false);

        if ($captcha_version === 'v2') {
            // security[re_captcha][field_title]
            $security_re_captcha_field_title = isset($ultimate_security_options['security']['re_captcha']['field_title']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['field_title'])) : '';
            if ($security_re_captcha_field_title)
                echo '<label for="user_pass">' . esc_html($security_re_captcha_field_title) . '</label>';

            echo '<div class="g-recaptcha ultimate-security-g-recaptcha ' . esc_attr($size) . '-g-recaptcha" data-sitekey="' . esc_attr($site_key) . '" data-theme="' . esc_attr($theme) . '" data-size="' . esc_attr($size) . '" ></div>';
        } elseif ($captcha_version === 'v3') {
            // Hidden token field for v3 with unique ID to avoid conflicts
            $unique_id = 'g-recaptcha-response-' . uniqid();
            echo '<input type="hidden" name="g-recaptcha-response" id="' . esc_attr($unique_id) . '" class="g-recaptcha-response-field">';

            // Register/enqueue the official reCAPTCHA v3 script (loads async when in footer).
            // Use ?render=SITE_KEY so grecaptcha.execute works without additional parameters.
            wp_enqueue_script(
                'ultimate-security-google-recaptcha',
                'https://www.google.com/recaptcha/api.js?render=' . rawurlencode($site_key),
                array(),
                null,
                true
            );

            // Also add the script directly for immediate loading on WooCommerce pages
            if (function_exists('is_woocommerce') && (is_woocommerce() || is_account_page())) {
                echo '<script src="https://www.google.com/recaptcha/api.js?render=' . esc_attr($site_key) . '" async defer></script>';
            }

            // Add an inline script (attached to the same handle) that defines the site key
            // and token generation logic. Uses wp_json_encode() so string quoting is safe.
            $inline = '
            var ultimateSecurityRecaptchaSiteKey = ' . wp_json_encode($site_key) . ';
            (function(){
                function generateRecaptchaToken(){
                    if (typeof grecaptcha !== "undefined") {
                        grecaptcha.ready(function() {
                            grecaptcha.execute(ultimateSecurityRecaptchaSiteKey, { action: "login" })
                                .then(function(token){
                                    // Update all token fields on the page
                                    var tokenFields = document.querySelectorAll("input[name=g-recaptcha-response]");
                                    tokenFields.forEach(function(field) {
                                        field.value = token;
                                    });
                                    console.log("reCAPTCHA token generated successfully");
                                })
                                .catch(function(error){
                                    console.error("reCAPTCHA token generation failed:", error);
                                    var tokenFields = document.querySelectorAll("input[name=g-recaptcha-response]");
                                    tokenFields.forEach(function(field) {
                                        if (!field.value) {
                                            field.value = "recaptcha-token-error";
                                        }
                                    });
                                });
                        });
                    } else {
                        generateRecaptchaToken.retryCount = (generateRecaptchaToken.retryCount || 0) + 1;
                        if (generateRecaptchaToken.retryCount < 6) {
                            setTimeout(generateRecaptchaToken, 500);
                        } else {
                            console.error("reCAPTCHA failed to load after multiple attempts");
                            var tokenFields = document.querySelectorAll("input[name=g-recaptcha-response]");
                            tokenFields.forEach(function(field) {
                                if (!field.value) {
                                    field.value = "recaptcha-failed-to-load";
                                }
                            });
                        }
                    }
                }

                document.addEventListener("DOMContentLoaded", function() {
                    // Generate initial token
                    setTimeout(generateRecaptchaToken, 500);
                    
                    // Also generate token immediately if grecaptcha is already loaded
                    if (typeof grecaptcha !== "undefined") {
                        setTimeout(generateRecaptchaToken, 100);
                    }
                    
                    // Handle all forms on the page
                    var forms = document.querySelectorAll("form");
                    forms.forEach(function(form) {
                        // Generate token on user interaction
                        form.addEventListener("focus", function(e) {
                            var t = e.target && e.target.tagName;
                            if (t === "INPUT" || t === "BUTTON" || t === "TEXTAREA" || t === "SELECT") {
                                generateRecaptchaToken();
                            }
                        }, true);

                        // Generate fresh token on form submit
                        form.addEventListener("submit", function(e) {
                            var tokenFields = form.querySelectorAll("input[name=g-recaptcha-response]");
                            if (tokenFields.length > 0) {
                                e.preventDefault();
                                var submitForm = function() {
                                    form.submit();
                                };
                                
                                if (typeof grecaptcha !== "undefined") {
                                    grecaptcha.ready(function() {
                                        grecaptcha.execute(ultimateSecurityRecaptchaSiteKey, { action: "login" })
                                            .then(function(token){
                                                tokenFields.forEach(function(field) {
                                                    field.value = token;
                                                });
                                                submitForm();
                                            })
                                            .catch(function(){
                                                console.error("reCAPTCHA token generation failed on submit");
                                                submitForm();
                                            });
                                    });
                                } else {
                                    submitForm();
                                }
                            }
                        });
                    });
                });
            })();
            ';

            wp_add_inline_script('ultimate-security-google-recaptcha', $inline);
        }

    }

    public static function verify_recaptcha_response($user)
    {
        if (is_wp_error($user)) {
            return $user;
        }

        // Skip reCAPTCHA verification if Turnstile is enabled for login (mutual exclusion)
        $ultimate_security_options = Utils::ultimate_security_get_option();
        $turnstile_enabled_for_login = isset($ultimate_security_options['security']['cloudflare_turnstile']['wordpress_login'])
            && $ultimate_security_options['security']['cloudflare_turnstile']['wordpress_login'];
        if ($turnstile_enabled_for_login) {
            return $user; // Turnstile handles login verification
        }

        $errors = new WP_Error();
        self::verify_recaptcha($errors);

        if ($errors->get_error_codes()) {
            return $errors;
        }

        return $user;
    }

    public static function verify_recaptcha_on_registration($username, $email, $errors)
    {
        self::verify_recaptcha($errors);
    }

    public static function verify_recaptcha_on_lostpassword()
    {
        $errors = new WP_Error();
        self::verify_recaptcha($errors);

        if ($errors->get_error_codes()) {
            wp_die(wp_kses_post($errors->get_error_message()));
        }
    }

    public static function verify_recaptcha_on_woocommerce_login($errors, $username)
    {
        self::verify_recaptcha($errors);
        return $errors;
    }

    public static function verify_recaptcha_on_woocommerce_register($username, $email, $errors)
    {
        self::verify_recaptcha($errors);
        return $errors;
    }

    private static function verify_recaptcha($errors = null)
    {
        // Test Mode: Log simulation and skip verification
        if (TestModeService::shouldSimulate()) {
            TestModeService::logSimulation(
                'google_recaptcha',
                'verification_bypassed',
                __('reCAPTCHA verification would be required', 'ultimate-security'),
                [
                    'has_response' => isset($_POST['g-recaptcha-response']),
                ]
            );
            return; // Skip verification
        }

        $ultimate_security_options = Utils::ultimate_security_get_option();
        // security[re_captcha][secret_key]
        $secret_key = isset($ultimate_security_options['security']['re_captcha']['secret_key']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['secret_key'])) : '';
        // security[re_captcha][type]
        $captcha_version = isset($ultimate_security_options['security']['re_captcha']['type']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['type'])) : 'v2';

        // security[re_captcha][message_verification_failed]
        $error_verification_failed = isset($ultimate_security_options['security']['re_captcha']['message_verification_failed']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['message_verification_failed'])) : esc_html__('Google reCAPTCHA verification failed. please try again.', 'ultimate-security');
        // security[re_captcha][message_blank]
        $error_blank = isset($ultimate_security_options['security']['re_captcha']['message_blank']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['message_blank'])) : esc_html__('Google reCAPTCHA token is missing', 'ultimate-security');
        // security[re_captcha][message_server_fail]
        $error_server_connection = isset($ultimate_security_options['security']['re_captcha']['message_server_fail']) ? sanitize_text_field(wp_unslash($ultimate_security_options['security']['re_captcha']['message_server_fail'])) : esc_html__('Could not get response from reCAPTCHA server', 'ultimate-security');

        if (!$secret_key) {
            return;
        }
        $response = '';
        // Check if the nonce is present in the form submission
        $nonce_valid = false;
        if (isset($_POST['ultimate_security_login_nonce_field'])) {
            $nonce_valid = wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['ultimate_security_login_nonce_field'])), 'ultimate_security_login_nonce_action');
        }

        // For WooCommerce forms, also check if this is a WooCommerce request
        $referer = '';

        if (isset($_SERVER['HTTP_REFERER'])) {
            $referer = wp_unslash($_SERVER['HTTP_REFERER']);
        }

        $is_wc_api = false;

        if ($referer) {
            $parsed = wp_parse_url($referer);
            if (isset($parsed['query']) && strpos($parsed['query'], 'wc-api=') !== false) {
                $is_wc_api = true;
            }
        }

        $is_woocommerce_request = (
            isset($_POST['woocommerce-login-nonce']) ||
            isset($_POST['woocommerce-register-nonce']) ||
            $is_wc_api ||
            (
                isset($_POST['action']) &&
                in_array(
                    wp_unslash($_POST['action']),
                    ['woocommerce_login', 'woocommerce_register'],
                    true
                )
            )
        );


        // Temporarily be more permissive for debugging
        if ($nonce_valid || $is_woocommerce_request || isset($_POST['g-recaptcha-response'])) {
            $response = isset($_POST['g-recaptcha-response']) ? sanitize_text_field(wp_unslash($_POST['g-recaptcha-response'])) : '';
        }

        $remote_ip = IpHelper::getClientIp();

        $verify_url = 'https://www.google.com/recaptcha/api/siteverify';
        $response_data = wp_remote_post($verify_url, [
            'body' => [
                'secret' => $secret_key,
                'response' => $response,
                'remoteip' => $remote_ip,
            ],
        ]);

        if (is_wp_error($response_data)) {
            return self::return_error($errors, $error_server_connection);
        }

        $response_body = wp_remote_retrieve_body($response_data);
        $result = json_decode($response_body, true);

        if (empty($result['success']) || ($captcha_version === 'v3' && isset($result['score']) && $result['score'] < 0.5)) {
            // Log detailed error for debugging
            return self::return_error($errors, $error_verification_failed);
        }
    }

    private static function return_error($errors, $message)
    {
        if ($errors instanceof WP_Error) {
            $errors->add('captcha_error', $message);
        } else {
            wp_die('<strong>Error:</strong> ' . esc_html($message));
        }
    }
    public static function custom_login_inline_scripts()
    {
        $ultimate_security_options = Utils::ultimate_security_get_option();
        $no_conflict_mode = isset($ultimate_security_options['security']['re_captcha']['no_conflict_mode']) ? $ultimate_security_options['security']['re_captcha']['no_conflict_mode'] : '0';
        ?>
        <style type="text/css">
            /* Custom login page styles */
            .normal-g-recaptcha {
                transform: scale(0.9);
                -webkit-transform: scale(0.9);
                transform-origin: 0 0;
                -webkit-transform-origin: 0 0;
            }
        </style>
        <script>
            window.ultimate_security_no_conflict = <?php echo $no_conflict_mode === '1' ? 'true' : 'false'; ?>;

            function removeGRecaptchaElements() {
                // Select all elements with 'g-recaptcha' class
                const gRecaptchaElements = document.querySelectorAll('.g-recaptcha');

                // Iterate through the elements
                gRecaptchaElements.forEach(element => {
                    // Check if the element does NOT have 'ultimate-security-g-recaptcha' class
                    if (!element.classList.contains('ultimate-security-g-recaptcha')) {
                        // Remove the element
                        element.remove();
                    }
                });
            }

            // Call on DOM ready if no-conflict mode is enabled
            document.addEventListener('DOMContentLoaded', function () {
                if (typeof window.ultimate_security_no_conflict !== 'undefined' && window.ultimate_security_no_conflict) {
                    removeGRecaptchaElements();
                }
            });
        </script>
        <?php
    }
}
