<?php

require_once SITEGUARD_PATH . 'really-simple-captcha/siteguard-really-simple-captcha.php';

class SiteGuard_CAPTCHA extends SiteGuard_Base {
	protected $captcha;
	protected $prefix;
	protected $word;

	private $last_check_result = null;
	private $last_check_prefix = null;

	function __construct() {
		global $siteguard_config;
		if ( '1' == $siteguard_config->get( 'captcha_enable' ) && 'xmlrpc.php' != basename( $_SERVER['SCRIPT_NAME'] ) && ! is_admin() ) {
			$this->captcha = new SiteGuardReallySimpleCaptcha();

			add_filter( 'shake_error_codes', array( $this, 'handler_shake_error_codes' ) );

			// for logiin
			if ( '0' !== $siteguard_config->get( 'captcha_login' ) ) {
				add_filter( 'login_form', array( $this, 'handler_login_form' ) );
				add_filter( 'wp_authenticate_user', array( $this, 'handler_wp_authenticate_user' ), 1, 2 );
			}
			// for lost password
			if ( '0' !== $siteguard_config->get( 'captcha_lostpasswd' ) ) {
				add_filter( 'lostpassword_form', array( $this, 'handler_lostpassword_form' ) );
				add_filter( 'lostpassword_post', array( $this, 'handler_lostpassword_post' ), 1 );
			}
			// for register user
			if ( '0' !== $siteguard_config->get( 'captcha_registuser' ) ) {
				add_filter( 'register_form', array( $this, 'handler_register_form' ) );
				add_action( 'registration_errors', array( $this, 'handler_registration_errors' ), 10, 3 );
			}
			// for comment
			if ( '0' !== $siteguard_config->get( 'captcha_comment' ) ) {
				add_action( 'comment_form_after_fields', array( $this, 'handler_comment_form' ), 1 );
				add_action( 'comment_form_logged_in_after', array( $this, 'handler_comment_form' ), 1 );
				add_action( 'comment_form', array( $this, 'handler_comment_form' ) );
				add_filter( 'preprocess_comment', array( $this, 'handler_process_comment_post' ) );
				add_action( 'wp_footer', array( $this, 'comment_captcha_reload_script' ) );
			}
		}
		if ( '1' == $siteguard_config->get( 'same_login_error' ) ) {
			add_filter( 'login_errors', array( $this, 'handler_login_errors' ) );
		}
	}
	private function check_captcha_with_cache() {
		$current_prefix = isset( $_POST['siteguard_captcha_prefix'] ) ? $_POST['siteguard_captcha_prefix'] : '';
		if ( $this->last_check_prefix !== $current_prefix ) {
			$this->last_check_result = null;
			$this->last_check_prefix = $current_prefix;
		}
		if ( null !== $this->last_check_result ) {
			return $this->last_check_result;
		}
	
		$is_ok = false;
		if ( array_key_exists( 'siteguard_captcha', $_POST ) && array_key_exists( 'siteguard_captcha_prefix', $_POST ) ) {
			$is_ok = $this->captcha->check( $_POST['siteguard_captcha_prefix'], $_POST['siteguard_captcha'], true );
		}
	
		$this->last_check_result = $is_ok;
		return $is_ok;
	}
	function check_requirements() {
		$error = siteguard_check_multisite();
		if ( is_wp_error( $error ) ) {
			return $error;
		}
		$error = $this->check_extensions();
		if ( is_wp_error( $error ) ) {
			return $error;
		}
		$error = $this->check_image_access();
		if ( is_wp_error( $error ) ) {
			return $error;
		}
		$error = $this->check_support_freetype();
		if ( is_wp_error( $error ) ) {
			return $error;
		}
		$error = $this->check_htaccess();
		if ( is_wp_error( $error ) ) {
			return $error;
		}
		return true;
	}
	function check_htaccess() {
		if ( false === SiteGuard_Htaccess::test_htaccess() ) {
			$message = esc_html__( 'mod_rewrite of .htaccess can not be used', 'siteguard' );
			$error   = new WP_Error( 'siteguard_captcha', $message );
			return $error;
		}
		return true;
	}
	function check_extensions() {
		$error_extensions = array();
		$extensions       = array(
			'mbstring',
			'gd',
		);
		foreach ( $extensions as $extension ) {
			if ( ! extension_loaded( $extension ) ) {
				$error_extensions[] = $extension;
			}
		}
		if ( empty( $error_extensions ) ) {
			return true;
		}

		$message  = esc_html__( 'In order to enable this function, it is necessary to install expanded modules', 'siteguard' );
		$message .= ' ( ';
		$message .= implode( ', ', $error_extensions );
		$message .= ' ) ';
		$message .= esc_html__( 'in the server.', 'siteguard' );

		$error = new WP_Error( 'siteguard_captcha', $message );
		return $error;
	}
	function check_image_access() {
		if ( is_object( $this->captcha ) ) {
			$ret = $this->captcha->make_tmp_dir();
		} else {
			$captcha = new SiteGuardReallySimpleCaptcha();
			$ret     = $captcha->make_tmp_dir();
		}
		if ( false === $ret ) {
			$message = esc_html__( 'The image file write failed.', 'siteguard' );
			$error   = new WP_Error( 'siteguard_captcha', $message );
			return $error;
		}

		return true;
		// $result = wp_remote_get( SITEGUARD_URL_PATH . 'really-simple-captcha/tmp/dummy.png' );
		// if ( ! is_wp_error( $result ) && 200 === $result['response']['code'] ) {
		// return true;
		// }

		// $message  = esc_html__( 'The image file access failed.', 'siteguard' );
		// if ( is_wp_error( $result ) ) {
		// $error_detail = '( Error: ' . $result->get_error_message( ) . ' )';
		// } else {
		// $error_detail = '( ResponseCode: ' . $result['response']['code'] . ' )';
		// }
		// $error = new WP_Error( 'siteguard_captcha', $message . $error_detail);
		// return $error;
	}
	function check_support_freetype() {
		if ( function_exists( 'imagettftext' ) ) {
			return true;
		}
		$message = esc_html__( 'In order to enable this function, php must be compiled with FreeType support enabled.', 'siteguard' );
		$error   = new WP_Error( 'siteguard_captcha', $message );
		return $error;
	}
	function handler_login_errors( $error ) {
		if ( strlen( $error ) > 0 && false === strpos( $error, esc_html__( 'ERROR: LOGIN LOCKED', 'siteguard' ) ) ) {
			$error = esc_html__( 'ERROR: Please check the input and resend.', 'siteguard' );
		}
		return $error;
	}
	function handler_shake_error_codes( $shake_error_codes ) {
		array_push( $shake_error_codes, 'siteguard-captcha-error' );
		return $shake_error_codes;
	}

	function init() {
		global $siteguard_config;
		$errors = $this->check_requirements();
		if ( ! is_wp_error( $errors ) ) {
			$switch = '1';
		} else {
			$switch = '0';
		}
		$siteguard_config->set( 'captcha_enable', $switch );
		$language = get_bloginfo( 'language' );
		if ( 'ja' == $language ) {
			$mode = '1'; // hiragana
		} else {
			$mode = '2'; // alphanumeric
		}
		$siteguard_config->set( 'captcha_login', $mode );
		$siteguard_config->set( 'captcha_comment', $mode );
		$siteguard_config->set( 'captcha_lostpasswd', $mode );
		$siteguard_config->set( 'captcha_registuser', $mode );
		if ( true === siteguard_check_multisite() ) {
			$siteguard_config->set( 'same_login_error', '1' );
		} else {
			$siteguard_config->set( 'same_login_error', '0' );
		}
		$siteguard_config->update();
	}
	function get_captcha() {
		$result  = '<p>';
		$result .= '<img src="' . WP_CONTENT_URL . '/siteguard/' . $this->prefix . '.png" alt="CAPTCHA">';
		$result .= '</p><p>';
		$result .= '<label for="siteguard_captcha">' . esc_html__( 'Please input characters displayed above.', 'siteguard' ) . '</label><br />';
		$result .= '<input type="text" name="siteguard_captcha" id="siteguard_captcha" class="input" value="" size="10" aria-required="true" />';
		$result .= '<input type="hidden" name="siteguard_captcha_prefix" id="siteguard_captcha_prefix" value="' . $this->prefix . '" />';
		$result .= '</p>';

		return $result;
	}
	function put_captcha() {
		$this->word   = $this->captcha->generate_random_word();
		$this->prefix = siteguard_rand();
		$this->captcha->generate_image( $this->prefix, $this->word );
		echo $this->get_captcha();
	}
	function handler_login_form() {
		global $siteguard_config;
		( '2' === $siteguard_config->get( 'captcha_login' ) ) ? $this->captcha->set_lang_mode( 'en' ) : $this->captcha->set_lang_mode( 'jp' );
		$this->put_captcha();
	}
	function handler_comment_form( $post_id ) {
		global $siteguard_config;
		if ( defined( 'SITEGUARD_PUT_COMMENT_FORM' ) ) {
			return;
		}
		( '2' === $siteguard_config->get( 'captcha_comment' ) ) ? $this->captcha->set_lang_mode( 'en' ) : $this->captcha->set_lang_mode( 'jp' );
		$this->put_captcha();
		define( 'SITEGUARD_PUT_COMMENT_FORM', '1' );
	}
	function handler_lostpassword_form() {
		global $siteguard_config;
		( '2' === $siteguard_config->get( 'captcha_lostpasswd' ) ) ? $this->captcha->set_lang_mode( 'en' ) : $this->captcha->set_lang_mode( 'jp' );
		$this->put_captcha();
	}
	function handler_register_form() {
		global $siteguard_config;
		( '2' == $siteguard_config->get( 'captcha_registuser' ) ) ? $this->captcha->set_lang_mode( 'en' ) : $this->captcha->set_lang_mode( 'jp' );
		$this->put_captcha();
	}
	function handler_wp_authenticate_user( $user, $password ) {
		if ( array_key_exists( 'siteguard_captcha', $_POST ) && array_key_exists( 'siteguard_captcha_prefix', $_POST ) ) {
			if ( $this->check_captcha_with_cache() ) {
				return $user;
			}
		}
		$error = new WP_Error();
		$error->add( 'siteguard-captcha-error', esc_html__( 'ERROR: Invalid CAPTCHA.', 'siteguard' ) );
		return $error;
	}
	function add_captcha_error() {
		return new WP_Error( 'siteguard-captcha-error', esc_html__( 'ERROR: Invalid CAPTCHA.', 'siteguard' ) );
	}
	function handler_lostpassword_post() {
		if ( array_key_exists( 'siteguard_captcha', $_POST ) && array_key_exists( 'siteguard_captcha_prefix', $_POST ) ) {
			if ( $this->check_captcha_with_cache() ) {
				return;
			}
		}
		add_filter( 'allow_password_reset', array( $this, 'add_captcha_error' ) );
	}
	function handler_registration_errors( $errors, $sanitized_user_login, $user_email ) {
		if ( array_key_exists( 'siteguard_captcha', $_POST ) && array_key_exists( 'siteguard_captcha_prefix', $_POST ) ) {
			if ( $this->check_captcha_with_cache() ) {
				return $errors;
			}
		}
		$new_errors = new WP_Error();
		$new_errors->add( 'siteguard-captcha-error', esc_html__( 'ERROR: Invalid CAPTCHA.', 'siteguard' ) );
		return $new_errors;
	}
	function handler_process_comment_post( $comment ) {
		if ( is_admin() ) {
			return $comment;
		}
		if ( array_key_exists( 'siteguard_captcha', $_POST ) && array_key_exists( 'siteguard_captcha_prefix', $_POST ) ) {
			if ( ! empty( $_POST['siteguard_captcha'] ) ) {
				if ( $this->check_captcha_with_cache( ) ) {
					return $comment;
				}
			}
		}
		wp_die( esc_html__( 'ERROR: Invalid CAPTCHA.', 'siteguard' ), esc_html( 'ERROR'), array( 'back_link' => true ) );
	}
	public function comment_captcha_reload_script( ) {
		if ( is_singular() && comments_open() ) {
			?>
			<script>
			window.addEventListener('pageshow', function(event) {
				var isBackForward = false;
				if (window.performance && typeof performance.getEntriesByType === 'function') {
					var perfEntries = performance.getEntriesByType('navigation');
					isBackForward = perfEntries.length > 0 && perfEntries[0].type === 'back_forward';
				}
				if (event.persisted || isBackForward) {
					window.location.reload();
				}
			});
			</script>
			<?php
		}
	}
}
