<?php
/**
 * reCAPTCHA class
 */
namespace owpElementor;

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// Start Class
class OEW_reCAPTCHA {

	/**
	 * Start things up
	 */
	public function __construct() {

		$g_version = get_option( 'owp_recaptcha_version' );
		$site_key = 'v3' == $g_version ? get_option( 'owp_recaptcha3_site_key' ) : get_option( 'owp_recaptcha_site_key' );
		$secret_key = 'v3' == $g_version ? get_option( 'owp_recaptcha3_secret_key' ) : get_option( 'owp_recaptcha_secret_key' );

		$cf_site_key      = get_option( 'owp_turnstile_site_key' );
		$cf_secret_key    = get_option( 'owp_turnstile_secret_key' );

		if ( ! empty( $site_key ) || ! empty( $secret_key ) ) {
			add_action( 'wp_enqueue_scripts', array( $this, 'recaptcha_script' ) );
		}

		if ( ! empty( $cf_site_key ) || ! empty( $cf_secret_key ) ) {
			add_action( 'wp_enqueue_scripts', array( $this, 'turnstile_script' ) );
		}

		add_filter( 'registration_errors', array( $this, 'oew_validate_registration_forms' ), 20, 3 );
		add_action( 'lostpassword_post', array( $this, 'oew_validate_lostpass_forms' ), 10, 2 );
		if ( is_multisite() ) {
			add_filter( 'wpmu_validate_user_signup', array( $this, 'oew_wpmu_validate_signup' ) );
			add_filter( 'wpmu_validate_blog_signup', array( $this, 'oew_wpmu_validate_signup' ) );
		}
	}

	/**
	 * Enqueues scripts
	 *
	 * @since 1.1.0
	 */
	public function recaptcha_script() {

		if ( 'v3' == get_option( 'owp_recaptcha_version' ) ) {
			wp_enqueue_script(
				'recaptcha',
				add_query_arg(
					array(
						'hl' => str_replace( '_', '-', get_locale() ),
						'render' => get_option( 'owp_recaptcha3_site_key' ),
					),
					'https://www.google.com/recaptcha/api.js'
				)
			);
			wp_enqueue_script( 'jquery' );
			wp_enqueue_script( 'recaptcha-v3-init', plugin_dir_url( OWP_ELEMENTOR__FILE__ ) . 'assets/js/recaptcha-v3-init.js', array( 'jquery', 'recaptcha' ), OWP_ELEMENTOR_VERSION, true );
			wp_localize_script( 'oew-login', 'RecaptchaV3InitParam', [
				'key' => get_option( 'owp_recaptcha3_site_key' ),
			] );
		} else {
			wp_enqueue_script(
				'recaptcha',
				add_query_arg(
					array(
						'hl' => str_replace( '_', '-', get_locale() ),
					),
					'https://www.google.com/recaptcha/api.js'
				)
			);
		}
	}

	public function oew_validate_registration_forms( $errors, $user_login, $user_email ) {

        if ( ! $errors instanceof \WP_Error ) {
            $errors = new \WP_Error();
        }

        if (!isset($_POST['oew_register_form']) || $_POST['oew_register_form'] !== '1') {
            return $errors;
        }

        if (defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST) {
            return $errors;
        }

        if (defined( 'REST_REQUEST' ) && REST_REQUEST) {
            return $errors;
        }

        do_action('oew_before_registration_validation', $errors);

        $token_method    = isset( $_POST['oew_register_validation_method'] ) ? $_POST['oew_register_validation_method'] : '';

        // Google reCAPTCHA Validation
        if ($token_method == 'google_recaptcha') {
            $response_token  = isset($_POST['g-recaptcha-response']) ? $_POST['g-recaptcha-response'] : '';

            if (!empty($response_token)) {
                $recaptcha_validate_result = self::recaptcha_validate($response_token);

                if (is_wp_error($recaptcha_validate_result)) {
                    $error_message = wp_strip_all_tags($recaptcha_validate_result->get_error_message());
                    $errors->add('recaptcha-failed', $error_message);
                }
            } else {
                $error_message = __('reCAPTCHA verification failed. Please try again.', 'ocean-popup-login');
                $errors->add('invalid-input-response', $error_message);
            }

        } elseif ($token_method == 'cloudflare_turnstile') {
            $response_token  = isset($_POST['cf-turnstile-response']) ? $_POST['cf-turnstile-response'] : '';

            if (!empty($response_token)) {
                $turnstile_validate_result = self::turnstile_validate($response_token);

                if (is_wp_error($turnstile_validate_result)) {
                    $error_message = wp_strip_all_tags($turnstile_validate_result->get_error_message());
                    $errors->add('turnstile-failed', $error_message);
                }
            } else {
                $error_message = __('Turnstile verification failed. Please try again.', 'ocean-popup-login');
                $errors->add('invalid-input-response', $error_message);
            }
        }

        return $errors;
    }

	public function oew_wpmu_validate_signup( $result ) {

		if ( ! $result['errors'] instanceof \WP_Error ) {
			$result['errors'] = new \WP_Error();
		}

		if (!isset($_POST['oew_register_form']) || $_POST['oew_register_form'] !== '1') {
			return $result;
		}

		$token_method = isset( $_POST['oew_register_validation_method'] ) ? $_POST['oew_register_validation_method'] : '';

		if ($token_method == 'google_recaptcha') {
			$response_token  = isset($_POST['g-recaptcha-response']) ? $_POST['g-recaptcha-response'] : '';
			if (!empty($response_token)) {
                $recaptcha_validate_result = self::recaptcha_validate($response_token);

                if (is_wp_error($recaptcha_validate_result)) {
                    $error_message = wp_strip_all_tags($recaptcha_validate_result->get_error_message());
                    $result['errors']->add('recaptcha-failed', $error_message);
                }
            } else {
                $error_message = __('reCAPTCHA verification failed. Please try again.', 'ocean-popup-login');
                $result['errors']->add('invalid-input-response', $error_message);
            }
		} elseif ($token_method == 'cloudflare_turnstile') {
			$response_token  = isset($_POST['cf-turnstile-response']) ? $_POST['cf-turnstile-response'] : '';
			if (!empty($response_token)) {
                $turnstile_validate_result = self::turnstile_validate($response_token);

                if (is_wp_error($turnstile_validate_result)) {
                    $error_message = wp_strip_all_tags($turnstile_validate_result->get_error_message());
					$result['errors']->add('turnstile-failed', $error_message);
                }
            } else {
                $error_message = __('Turnstile verification failed. Please try again.', 'ocean-popup-login');
                $result['errors']->add('invalid-input-response', $error_message);
            }
		}

		return $result;
	}

	public function oew_validate_lostpass_forms( $errors, $user = null ) {

		if ( ! $errors instanceof \WP_Error ) {
            $errors = new \WP_Error();
        }

        if (!isset($_POST['oew_lostpass_form']) || $_POST['oew_lostpass_form'] !== '1') {
            return $errors;
        }

		if (empty($_POST['user_login'])) {
			return $errors;
		}

		$token_method = isset( $_POST['oew_lostpass_validation_method'] ) ? $_POST['oew_lostpass_validation_method'] : '';

		if ($token_method == 'google_recaptcha') {
            $response_token  = isset($_POST['g-recaptcha-response']) ? $_POST['g-recaptcha-response'] : '';

            if (!empty($response_token)) {
                $recaptcha_validate_result = self::recaptcha_validate($response_token);

                if (is_wp_error($recaptcha_validate_result)) {
                    $error_message = wp_strip_all_tags($recaptcha_validate_result->get_error_message());
                    $errors->add('recaptcha-failed', $error_message);
                }
            } else {
                $error_message = __('reCAPTCHA verification failed. Please try again.', 'ocean-popup-login');
                $errors->add('invalid-input-response', $error_message);
            }

        } elseif ($token_method == 'cloudflare_turnstile') {
            $response_token  = isset($_POST['cf-turnstile-response']) ? $_POST['cf-turnstile-response'] : '';

            if (!empty($response_token)) {
                $turnstile_validate_result = self::turnstile_validate($response_token);

                if (is_wp_error($turnstile_validate_result)) {
                    $error_message = wp_strip_all_tags($turnstile_validate_result->get_error_message());
                    $errors->add('turnstile-failed', $error_message);
                }
            } else {
                $error_message = __('Turnstile verification failed. Please try again.', 'ocean-popup-login');
                $errors->add('invalid-input-response', $error_message);
            }
        }

		return $errors;
	}


	/**
	 * Enqueues scripts
	 *
	 * @since 2.4.7
	 */
	public function turnstile_script() {

		$site_key      = get_option( 'owp_turnstile_site_key' );
		$render_method = get_option( 'owp_turnstile_render_method' );
		$render_method = $render_method ? $render_method : 'implicit';
		$theme_style   = get_option( 'owp_turnstile_theme' );
		$theme_style   = $theme_style ? $theme_style : 'auto';

		$locale = str_replace( '_', '-', get_locale() );
		$locale = strtolower($locale);

		if ( 'implicit' === $render_method ) {
			wp_enqueue_script(
				'cf-turnstile',
				'https://challenges.cloudflare.com/turnstile/v0/api.js',
				array(),
				null,
				true
			);
		} elseif( 'explicit' === $render_method ) {
			$script_args = array(
				'onload' => 'oew_form_turnstile_cb',
				'render' => 'explicit',
			);
			wp_enqueue_script(
				'owp-cf-turnstile',
				add_query_arg( $script_args, 'https://challenges.cloudflare.com/turnstile/v0/api.js' ),
				array(),
				null,
				true
			);

			$inline_script = "function oew_form_turnstile_cb() {
					var containers = document.querySelectorAll('#owp-turnstile-container');
					if (containers.length) {
						containers.forEach(function(container) {
							turnstile.render(container, {
								sitekey: '" . $site_key . "',
								theme: '" . $theme_style . "',
								language: '" . $locale . "'
							});
						});
					}
				}
			";
			wp_add_inline_script( 'owp-cf-turnstile', $inline_script );
		}
	}

	/**
	 * Validates reCAPTCHA
	 *
	 * @since 1.1.0
	 * @access public
	 */
	public static function recaptcha_validate( $response, $remote_ip = '' ) {

		if ( empty( $remote_ip ) ) {
			$remote_ip = $_SERVER['REMOTE_ADDR'];
		}

		$response = wp_remote_post(
			'https://www.google.com/recaptcha/api/siteverify',
			array(
				'body' => array(
					'secret'   =>  'v3' == get_option( 'owp_recaptcha_version' ) ? get_option( 'owp_recaptcha3_secret_key' ) : get_option( 'owp_recaptcha_secret_key' ),
					'response' => $response,
					'remoteip' => $remote_ip,
				),
			)
		);

		$response_code    = wp_remote_retrieve_response_code( $response );
		$response_message = wp_remote_retrieve_response_message( $response );
		$response_body    = wp_remote_retrieve_body( $response );

		if ( 200 == $response_code ) {

			$result = json_decode( $response_body, true );

			if ( $result['success'] ) {
				return true;
			}

			$error_code = reset( $result['error-codes'] );
			return new \WP_Error( $error_code, self::get_validation_error( $error_code, 'reCaptcha' ) );
		}

		return new \WP_Error( 'recaptcha', 'recaptcha-not-reachable' );
	}

	/**
	 * Validates reCAPTCHA
	 *
	 * @since 2.4.7
	 * @access public
	 */
	public static function turnstile_validate( $response, $remote_ip = '' ) {

		if ( empty( $remote_ip ) ) {
			if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
				$remote_ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
			} else {
				$remote_ip = $_SERVER['REMOTE_ADDR'];
			}
		}

		$response = wp_remote_post(
			'https://challenges.cloudflare.com/turnstile/v0/siteverify',
			array(
				'body' => array(
					'secret'   => get_option( 'owp_turnstile_secret_key' ),
					'response' => $response,
					'remoteip' => $remote_ip,
				),
			)
		);

		$response_code = wp_remote_retrieve_response_code( $response );
		$response_body = wp_remote_retrieve_body( $response );

		if ( 200 == $response_code ) {

			$result = json_decode( $response_body, true );

			if ( $result['success'] ) {
				return true;
			}

			$error_code = reset( $result['error-codes'] );
			return new \WP_Error( $error_code, self::get_validation_error( $error_code, 'Turnstile' ) );
		}

		return new \WP_Error( 'bad-request', 'Unable to reach the Turnstile server.' );
	}

	/**
	 * Retrieves errors
	 *
	 * @since 2.4.7
	 *
	 * @param WP_Error $errors WP_Error object
	 * @return WP_Error WP_Error object
	 */
	public static function get_validation_error( $error_code, $type ) {
		switch ( $error_code ) {
			case 'missing-input-secret':
			case 'invalid-input-secret':
				return sprintf( __( 'Invalid %s secret key.', 'ocean-elementor-widgets' ), $type );
			case 'missing-input-response':
			case 'invalid-input-response':
				return __( 'Please check the box to prove that you are not a robot.', 'ocean-elementor-widgets' );
			case 'timeout-or-duplicate':
				return __( 'The token has expired. Please reload the page and try again.', 'ocean-elementor-widgets' );
			case 'bad-request':  // For Turnstile
			case 'recaptcha-not-reachable':  // For reCAPTCHA
			default:
				return sprintf( __( 'Unable to reach the %s server.', 'ocean-elementor-widgets' ), $type );
		}
	}

	public function oew_validate_recaptcha($recaptcha_token, $error_method = 'wp_error') {

		if (!empty($turnstile_token)) {
			$recaptcha_validate_result = self::recaptcha_validate($recaptcha_token);

			if (is_wp_error($recaptcha_validate_result)) {
				$error_message = wp_strip_all_tags($recaptcha_validate_result->get_error_message());
				return $errors->add('recaptcha-failed', $error_message);
			}
		} else {
			$error_message = __('reCaptcha verification failed. Please try again.', 'ocean-popup-login');
			return $errors->add('invalid-input-response',$error_message);
		}

		return true;
	}

	public function oew_validate_turnstile($turnstile_token, $error_method = 'wp_error') {

		if (!empty($turnstile_token)) {
			$turnstile_validate_result = self::turnstile_validate($turnstile_token);

			if (is_wp_error($turnstile_validate_result)) {
				$error_message = wp_strip_all_tags($turnstile_validate_result->get_error_message());
				return $errors->add('turnstile-failed', $error_message);
			}
		} else {
			$error_message = __('Turnstile verification failed. Please try again.', 'ocean-popup-login');
			return $errors->add('invalid-input-response',$error_message);
		}

		return true;
	}

}
new OEW_reCAPTCHA();
