<?php
/**
 * This class adds the required No More Bots fields to the WordPress login/register/reset-password forms.
 *
 *
 * @author     FutrX
 * @year       2023
 * @package    NoMoreBots
 * @subpackage NoMoreBots\Hooks\Forms
 */

namespace NoMoreBots\Hooks\Forms;

use NoMoreBots\Utils\Modules;

class WP {

	/**
	 * Return a single instance of this class across the application.
	 *
	 * @return WP|null
	 */
	public static function instance(): ?WP {
		static $instance = null;
		if ( null === $instance ) {
			$instance = new WP();
		}

		return $instance;
	}

	public function __construct() {
		add_action( 'login_form', array( $this, 'loginForm' ) );
		add_action( 'lostpassword_form', array( $this, 'lostPasswordForm' ) );
		add_action( 'register_form', array( $this, 'registerForm' ) );
	}


	/**
	 * Adds the required fields to the WP Login form.
	 *
	 * This will be loaded on the WP forms:
	 *  - wp-login.php
	 *  - wp-login.php?action=login
	 *
	 * @return void
	 */
	public function loginForm(): void {
		if ( Modules::isActive( 'hp' ) && self::shouldInject( 'loginform', 'HP' ) ) {
			echo self::hpField();
		}

		if ( Modules::isActive( 'otp' ) && self::shouldInject( 'loginform', 'OTP' ) ) {
			echo self::otpField();
		}
	}

	/**
	 * Adds the required fields to the WP Lost Password form.
	 *
	 * This will be loaded on the WP forms:
	 *  - wp-login.php?action=lostpassword
	 *
	 * @return void
	 */
	public function lostPasswordForm(): void {
		if ( Modules::isActive( 'hp' ) && self::shouldInject( 'lostpasswordform', 'HP' ) ) {
			echo self::hpField();
		}
		if ( Modules::isActive( 'otp' ) && self::shouldInject( 'lostpasswordform', 'OTP' ) ) {
			echo self::otpField();
		}
	}

	/**
	 * Adds the required fields to the WP Register form.
	 *
	 * This will be loaded on the WP forms:
	 *  - wp-login.php?action=register
	 *
	 * @return void
	 */
	public function registerForm(): void {
		if ( Modules::isActive( 'hp' ) && self::shouldInject( 'registerform', 'HP' ) ) {
			echo self::hpField();
		}
		if ( Modules::isActive( 'otp' ) && self::shouldInject( 'registerform', 'OTP' ) ) {
			echo self::otpField();
		}
	}


	/**
	 * Returns the HTML for the HoneyPot field.
	 *
	 * @return false|string
	 */
	private static function hpField(): string {
		ob_start();
		// Get random fields from the predefined list.
		$random_field_type = array_rand( NOMOREBOTS_INPUT_TYPES );
		$random_field      = NOMOREBOTS_INPUT_TYPES[ $random_field_type ];
		$fieldClass        = esc_attr( NOMOREBOTS_HONEYPOT_FIELD_PREFIX );
		$fieldId           = esc_attr( NOMOREBOTS_HONEYPOT_FIELD_PREFIX ) . '-' . rand( 1, 100 );
		?>
		<style>
			<?php echo esc_html( ".{$fieldClass} { display: none !important; }" ); ?>
		</style>
		<input
				type="<?php echo esc_attr( $random_field['type'] ); ?>"
				name="<?php echo $fieldId; ?>"
				id="<?php echo $fieldId; ?>"
				class="<?php echo $fieldClass; ?>"
				value=""
				autocomplete="off"
				placeholder="<?php echo esc_attr( $random_field['placeholder'] ); ?>"
				aria-label="<?php echo esc_attr( $random_field['label'] ); ?>"/>
		<?php
		return ob_get_clean();
	}

	/**
	 * Returns the HTML for the OTP field.
	 *
	 * //TODO This needs to be updated from Javascript to pure PHP to allow for OTP shield to be generated on the server side.A two step verification is required (before submitting the register form).
	 *
	 * @return string
	 */
	private static function otpField(): string {
		ob_start();
		// Add nonce field to the form
		wp_nonce_field( NOMOREBOTS_OTP_FIELD_PREFIX . '_nonce', NOMOREBOTS_OTP_FIELD_PREFIX . '_nonce' );
		?>
		<script id='<?php echo esc_attr( NOMOREBOTS_PLUGINTEXTDOMAIN ); ?>'
				src="<?php echo esc_attr( NOMOREBOTS_PLUGINURL . 'assets/js/OTP.js' ); ?>"
				data-nonce="<?php echo esc_attr( wp_create_nonce( NOMOREBOTS_OTP_FIELD_PREFIX . '_nonce' ) ); ?>"
				data-rest-url="<?php echo esc_attr( esc_url( rest_url() ) ); ?>">

		</script>
		<?php
		return ob_get_clean();
	}

	/**
	 * Helper function that decides if the HoneyPot field should be injected into this WP form or no.
	 *
	 * @param string $formId    The ID of the form.
	 * @param string $type      The type of the form, allowed:
	 *                          - HP
	 *                          - OTP
	 *
	 * @return bool
	 */
	private static function shouldInject( string $formId, string $type ): bool {
		switch ( $type ) {
			case 'OTP':
				$otpWPForms = get_option( NOMOREBOTS_OTP_FIELD_PREFIX . NOMOREBOTS_WP_FORMS_META_KEY );
				if ( ! is_array( $otpWPForms ) || ! in_array( $formId, $otpWPForms ) ) {
					return false;
				}

				return true;
			default:
				$hpWPForms = get_option( NOMOREBOTS_HONEYPOT_FIELD_PREFIX . NOMOREBOTS_WP_FORMS_META_KEY );
				if ( ! is_array( $hpWPForms ) || ! in_array( $formId, $hpWPForms ) ) {
					return false;
				}

				return true;
		}
	}
}
