<?php
/**
 * @author      FutrX
 * @year        2023
 * @package     futrx.com
 * @subpackage  NoMoreBots\Rest
 * @endpoints   wp-json\nmb\v1\otp\generate
 *              wp-json\nmb\v1\otp\validate
 */

namespace NoMoreBots\Rest;

use WP_REST_Request;
use WP_REST_Response;
use NoMoreBots\Utils\OTP\OTP as OTPGenerator;

class OTP {

	public function __construct() {
		add_action(
			'rest_api_init',
			function () {
				// wp-json/nmb/v1/otp/generate
				register_rest_route(
					'nmb/v1',
					'/otp/generate',
					array(
						'methods'             => 'POST',
						'callback'            => array( $this, 'generateOTP' ),
						'permission_callback' => array( $this, 'permissionValidate' ),
					)
				);
				// wp-json/nmb/v1/otp/validate
				register_rest_route(
					'nmb/v1',
					'/otp/validate',
					array(
						'methods'             => 'POST',
						'callback'            => array( $this, 'validateOTP' ),
						'permission_callback' => array( $this, 'permissionValidate' ),
					)
				);
			}
		);
	}

	/**
	 * Generates a new OTP for the user.
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return WP_REST_Response
	 */
	public function generateOTP( WP_REST_Request $request ): WP_REST_Response {
		$jsonParams = $request->get_json_params();

		$secretKey     = get_option( NOMOREBOTS_OTP_FIELD_PREFIX . NOMOREBOTS_OTP_SECRET_KEY_META_KEY );
		$generatedCode = OTPGenerator::getTokenCode( $secretKey );

		// Send email.
		$emailSent = OTPGenerator::sendEmail( $jsonParams['email'], $generatedCode );
		if ( ! $emailSent ) {
			$data     = array(
				'response' => 'error',
				'message'  => __( 'Email could not be sent. Please try again later.', NOMOREBOTS_PLUGINTEXTDOMAIN ),
			);
			$response = rest_ensure_response( $data );
			$response->set_status( 400 );

			return $response;
		}

		$data = array(
			'response' => 'success',
			'email'    => $jsonParams['email'],
		);

		// send back a rest response.
		$response = rest_ensure_response( $data );
		if ( is_wp_error( $response ) ) {
			$response->set_status( 400 );

			return $response;
		}

		// success response.
		$response->set_status( 200 );

		return $response;
	}


	/**
	 * Validates the OTP for the user.
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return WP_REST_Response
	 */
	public function validateOTP( WP_REST_Request $request ): WP_REST_Response {
		$jsonParams = $request->get_json_params();
		$otpCode    = $jsonParams['otpCode'];

		$secretKey = get_option( NOMOREBOTS_OTP_FIELD_PREFIX . NOMOREBOTS_OTP_SECRET_KEY_META_KEY );
		$validated = OTPGenerator::verify( $secretKey, $otpCode );

		if ( ! $validated ) {
			$data     = array(
				'response' => 'error',
				'message'  => __( 'Invalid OTP code.', NOMOREBOTS_PLUGINTEXTDOMAIN ),
			);
			$response = rest_ensure_response( $data );
			$response->set_status( 400 );

			return $response;
		}

		$data = array(
			'response' => 'success',
			'message'  => __( 'OTP code validated successfully.', NOMOREBOTS_PLUGINTEXTDOMAIN ),
		);

		// send back a rest response.
		$response = rest_ensure_response( $data );
		if ( is_wp_error( $response ) ) {
			$response->set_status( 400 );

			return $response;
		}

		// success response.
		$response->set_status( 200 );

		return $response;
	}

	/**
	 * Validates the permission to access the endpoint.
	 *
	 * Right now, we are using nonce to validate the permission, which proves that the request is coming from the
	 * same site in the browser.
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return bool
	 */
	public function permissionValidate( WP_REST_Request $request ): bool {
		// validate using nonce.
		$nonce = $request->get_param( 'nonce' );
		if ( ! $nonce || ! wp_verify_nonce( $nonce, NOMOREBOTS_OTP_FIELD_PREFIX . '_nonce' ) ) {
			return false;
		}

		// TODO: Add more validation here, to prevent weirdos from accessing the endpoint.

		return true;
	}
}
