<?php
/**
 * Class used to define Password Strength Meter.
 *
 * @package automattic/jetpack-account-protection
 */

namespace Automattic\Jetpack\Account_Protection;

use Automattic\Jetpack\Assets\Logo as Jetpack_Logo;

/**
 * Class Password_Strength_Meter
 */
class Password_Strength_Meter {
	/**
	 * Validaton service instance
	 *
	 * @var Validation_Service
	 */
	private $validation_service;

	/**
	 * Validation_Service constructor.
	 *
	 * @param ?Validation_Service $validation_service Password manager instance.
	 */
	public function __construct( ?Validation_Service $validation_service = null ) {
		$this->validation_service = $validation_service ?? new Validation_Service();
	}

	/**
	 * Wrapper method for nonce verification.
	 *
	 * @param string $nonce  Nonce value.
	 * @param string $action Nonce action.
	 *
	 * @return bool
	 */
	protected function verify_nonce( string $nonce, string $action ): bool {
		return wp_verify_nonce( $nonce, $action );
	}

	/**
	 * Wrapper method for sending a JSON error response.
	 *
	 * @param string $message The error message.
	 *
	 * @return void
	 */
	protected function send_json_error( string $message ): void {
		// @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int.
		wp_send_json_error( array( 'message' => $message ), null, JSON_UNESCAPED_SLASHES );
	}

	/**
	 * Wrapper method for sending a JSON success response.
	 *
	 * @param array $data The data to send.
	 *
	 * @return void
	 */
	protected function send_json_success( array $data ): void {
		// @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int.
		wp_send_json_success( $data, null, JSON_UNESCAPED_SLASHES );
	}

	/**
	 * AJAX endpoint for password validation.
	 *
	 * @return void
	 */
	public function validate_password_ajax(): void {
		// phpcs:disable WordPress.Security.NonceVerification
		if ( ! isset( $_POST['password'] ) ) {
			$this->send_json_error( __( 'No password provided.', 'jetpack-account-protection' ) );
			return;
		}

		if ( ! isset( $_POST['nonce'] ) || ! $this->verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'validate_password_nonce' ) ) {
			$this->send_json_error( __( 'Invalid nonce.', 'jetpack-account-protection' ) );
			return;
		}

		$user_specific = false;
		if ( isset( $_POST['user_specific'] ) ) {
			$user_specific = filter_var( sanitize_text_field( wp_unslash( $_POST['user_specific'] ) ), FILTER_VALIDATE_BOOLEAN );
		}

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$password = wp_unslash( $_POST['password'] );
		// phpcs:enable WordPress.Security.NonceVerification
		$state = $this->validation_service->get_validation_state( $password, $user_specific );

		$this->send_json_success( array( 'state' => $state ) );
	}

	/**
	 * Enqueue the password strength meter script on the profile page.
	 *
	 * @return void
	 */
	public function enqueue_jetpack_password_strength_meter_profile_script(): void {
		global $pagenow;

		if ( ! isset( $pagenow ) || ! in_array( $pagenow, array( 'profile.php', 'user-new.php', 'user-edit.php' ), true ) ) {
			return;
		}

		$this->enqueue_script();
		$this->enqueue_styles();

		// Only profile page should run user specific checks.
		$this->localize_jetpack_data( 'profile.php' === $pagenow );
	}

	/**
	 * Enqueue the password strength meter script on the reset password page.
	 *
	 * @return void
	 */
	public function enqueue_jetpack_password_strength_meter_reset_script(): void {
		// No nonce verification necessary as the action includes a robust verification process
		// phpcs:ignore WordPress.Security.NonceVerification
		if ( isset( $_GET['action'] ) && ( 'rp' === $_GET['action'] || 'resetpass' === $_GET['action'] ) ) {
			$this->enqueue_script();
			$this->enqueue_styles();
			$this->localize_jetpack_data();
		}
	}

	/**
	 * Localize the Jetpack data for the password strength meter.
	 *
	 * @param bool $user_specific Whether or not to run user specific checks.
	 *
	 * @return void
	 */
	public function localize_jetpack_data( bool $user_specific = false ): void {
		$jetpack_logo = new Jetpack_Logo();

		wp_localize_script(
			'jetpack-password-strength-meter',
			'jetpackData',
			array(
				'ajaxurl'                => admin_url( 'admin-ajax.php' ),
				'nonce'                  => wp_create_nonce( 'validate_password_nonce' ),
				'userSpecific'           => $user_specific,
				'logo'                   => htmlspecialchars( $jetpack_logo->get_jp_emblem( true ), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ),
				'validationInitialState' => $this->validation_service->get_validation_initial_state( $user_specific ),
			)
		);
	}

	/**
	 * Enqueue the password strength meter script.
	 *
	 * @return void
	 */
	public function enqueue_script(): void {
		wp_enqueue_script(
			'jetpack-password-strength-meter',
			plugin_dir_url( __FILE__ ) . 'js/jetpack-password-strength-meter.js',
			array( 'jquery' ),
			Account_Protection::PACKAGE_VERSION,
			true
		);
	}

	/**
	 * Enqueue the password strength meter styles.
	 *
	 * @return void
	 */
	public function enqueue_styles(): void {
		wp_enqueue_style(
			'strength-meter-styles',
			plugin_dir_url( __FILE__ ) . 'css/strength-meter.css',
			array(),
			Account_Protection::PACKAGE_VERSION
		);
	}
}
