<?php
/**
 * Responsible for rendering the short codes.
 *
 * @package    wp2fa
 * @subpackage short-codes
 * @copyright  2026 Melapress
 * @license    https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
 * @link       https://wordpress.org/plugins/wp-2fa/
 */

declare(strict_types=1);

namespace WP2FA\Shortcodes;

use WP2FA\Core;
use WP2FA\WP2FA;
use WP2FA\Admin\User_Notices;
use WP2FA\Admin\Wizard_Integration;
use WP2FA\Utils\Settings_Utils;
use WP2FA\Admin\Helpers\WP_Helper;
use WP2FA\Admin\Views\Re_Login_2FA;
use WP2FA\Admin\Helpers\User_Helper;

if ( ! class_exists( '\WP2FA\Shortcodes\Shortcodes' ) ) {
	/**
	 * Class for rendering shortcodes.
	 */
	class Shortcodes {

		/**
		 * Constructor.
		 */
		public static function init() {
			\add_shortcode( 'wp-2fa-setup-form', array( __CLASS__, 'user_setup_2fa_form' ) );
			\add_shortcode( 'wp-2fa-setup-notice', array( __CLASS__, 'user_setup_2fa_notice' ) );
			//\add_action( 'wp_enqueue_scripts', array( __CLASS__, 'register_2fa_shortcode_scripts' ) );

			\add_filter( 'the_content', array( __CLASS__, 'maybe_hide_generated_by_text' ) );
		}

		/**
		 * Strips the "Page generated by WP 2FA Plugin" attribution text from the
		 * custom frontend 2FA page when the hide_page_generated_by setting is enabled.
		 *
		 * @param string $content The post content.
		 *
		 * @return string
		 *
		 * @since 2.8.0
		 */
		public static function maybe_hide_generated_by_text( $content ) {
			if ( ! \is_page() ) {
				return $content;
			}

			if ( ! \has_shortcode( $content, 'wp-2fa-setup-form' ) ) {
				return $content;
			}

			if ( ! WP2FA::get_wp2fa_white_label_setting( 'hide_page_generated_by' ) ) {
				return $content;
			}

			// Remove the attribution paragraph that was embedded in the page content at creation time.
			$content = \preg_replace(
				'#<p>\s*' . \preg_quote( \esc_html__( 'Page generated by', 'wp-2fa' ), '#' ) . '\s*<a [^>]*>.*?</a>\s*</p>#s',
				'',
				$content
			);

			return $content;
		}

		/**
		 * Register scripts and styles.
		 */
		public static function register_2fa_shortcode_scripts() {
			// Add our front end stuff, which we only want to load when the shortcode is present.
			\wp_register_script( 'wp_2fa_frontend_scripts', Core\script_url( 'wp-2fa', 'admin' ), array( 'jquery', 'wp_2fa_micro_modals', 'wp-i18n' ), WP_2FA_VERSION, true );
			\wp_register_script( 'wp_2fa_micro_modals', Core\script_url( 'micromodal', 'admin' ), array(), WP_2FA_VERSION, true );
			\wp_register_style( 'wp_2fa_styles', Core\style_url( 'styles', 'frontend' ), array(), WP_2FA_VERSION );

			$data_array = array(
				'ajaxURL'        => \admin_url( 'admin-ajax.php' ),
				'roles'          => WP_Helper::get_roles_wp(),
				'nonce'          => \wp_create_nonce( 'wp-2fa-settings-nonce' ),
				'codesPreamble'  => \esc_html__( 'These are the 2FA backup codes for the user', 'wp-2fa' ),
				'readyText'      => \esc_html__( 'I\'m ready', 'wp-2fa' ),
				'codeReSentText' => \esc_html__( 'New code sent', 'wp-2fa' ),
				'allDoneHeading' => \esc_html__( 'All done.', 'wp-2fa' ),
				'allDoneText'    => \esc_html__( 'Your login just got more secure.', 'wp-2fa' ),
				'closeWizard'    => \esc_html__( 'Close Wizard', 'wp-2fa' ),
				'invalidEmail'   => \esc_html__( 'Please use a valid email address', 'wp-2fa' ),
			);
			\wp_localize_script( 'wp_2fa_frontend_scripts', 'wp2faData', $data_array );

			$role = User_Helper::get_user_role();

			$re_login = Settings_Utils::get_setting_role( $role, Re_Login_2FA::RE_LOGIN_SETTINGS_NAME );

			$data_array                  = array(
				'ajaxURL'         => \admin_url( 'admin-ajax.php' ),
				'nonce'           => \wp_create_nonce( 'wp2fa-verify-wizard-page' ),
				'codesPreamble'   => \esc_html__( 'These are the 2FA backup codes for the user', 'wp-2fa' ),
				'readyText'       => \esc_html__( 'I\'m ready', 'wp-2fa' ),
				'codeReSentText'  => \esc_html__( 'New code sent', 'wp-2fa' ),
				'invalidEmail'    => \esc_html__( 'Please use a valid email address', 'wp-2fa' ),
				'backupCodesSent' => \esc_html__( 'Backup codes sent', 'wp-2fa' ),
				'reLogin'         => $re_login,
				'reLoginEnabled'  => Re_Login_2FA::ENABLED_SETTING_VALUE,
				'loginUrl'        => \wp_login_url(),
			);
			$redirect_page               = \sanitize_text_field( Settings_Utils::get_setting_role( $role, 'redirect-user-custom-page' ) );
			$redirect_page_global        = \sanitize_text_field( Settings_Utils::get_setting_role( null, 'redirect-user-custom-page' ) );
			$redirect_page_global_setting = \sanitize_text_field( Settings_Utils::get_setting_role( $role, 'redirect-user-custom-page-global' ) );

			// Priority: role-specific redirect-user-custom-page > global redirect-user-custom-page > redirect-user-custom-page-global > empty.
			if ( '' !== trim( (string) $redirect_page ) ) {
				$data_array['redirectToUrl'] = \trailingslashit( get_site_url() ) . $redirect_page;
			} elseif ( '' !== trim( (string) $redirect_page_global ) ) {
				$data_array['redirectToUrl'] = \trailingslashit( get_site_url() ) . $redirect_page_global;
			} elseif ( '' !== trim( (string) $redirect_page_global_setting ) ) {
				$data_array['redirectToUrl'] = \trailingslashit( get_site_url() ) . $redirect_page_global_setting;
			} else {
				$data_array['redirectToUrl'] = '';
			}

			// Check for shortcode parameter - if one is present use it to redirect the user - highest priority.
			if ( isset( $redirect_after ) && ! empty( $redirect_after ) ) {
				$candidate_url = \trailingslashit( \get_site_url() ) . \sanitize_text_field( $redirect_after );
				$validated     = \wp_validate_redirect( $candidate_url, '' );
				if ( ! empty( $validated ) ) {
					$data_array['redirectToUrl'] = $validated;
				}
			} elseif ( isset( $_GET['return'] ) && ! empty( $_GET['return'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
				$return_path   = \sanitize_text_field( \wp_unslash( $_GET['return'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
				$candidate_url = \trailingslashit( \get_site_url() ) . $return_path;
				$validated     = \wp_validate_redirect( $candidate_url, '' );
				if ( ! empty( $validated ) ) {
					$data_array['redirectToUrl'] = $validated;
				}
			}

			\wp_localize_script( 'wp_2fa_frontend_scripts', 'wp2faWizardData', $data_array );
		}

		/**
		 * Output setup form.
		 *
		 * @param array $atts - Array with the attributes passed to shortcode.
		 *
		 * @return string
		 */
		public static function user_setup_2fa_form( $atts ) {
			$atts = \shortcode_atts(
				array(
					'show_preamble'       => 'true',
					'redirect_after'      => '',
					'do_not_show_enabled' => 'false',
				),
				$atts
			);

			$show_preamble       = filter_var( $atts['show_preamble'], FILTER_VALIDATE_BOOLEAN );
			$redirect_after      = \sanitize_text_field( $atts['redirect_after'] );
			$do_not_show_enabled = filter_var( $atts['do_not_show_enabled'], FILTER_VALIDATE_BOOLEAN );

			/**
			 * Fires when the FE shortcode scripts are registered.
			 *
			 * @param bool $shortcodes - True if called from the short codes method.
			 *
			 * @since 2.2.0
			 */
			\do_action( WP_2FA_PREFIX . 'shortcode_scripts', true );

			if ( \is_user_logged_in() ) {

				$additional_args = array(
					'is_shortcode'  => true,
					'show_preamble' => $show_preamble,
					'options'       => array(
						'do_not_show_enabled' => $do_not_show_enabled,
					),
				);

				$user = \wp_get_current_user();

				ob_start();
				echo self::get_notification_style(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				echo '<div class="wp-2fa-shortcode-wrapper">';
				User_Notices::user_setup_2fa_nag( 'output_shortcode' );
				Wizard_Integration::render_profile_section_frontend( $user, $additional_args );
				echo '</div>';
				$content = ob_get_contents();
				ob_end_clean();

				return $content;
			} elseif ( ! \is_admin() && ! \is_user_logged_in() ) {
				ob_start();
				$new_page_id = WP2FA::get_wp2fa_setting( 'custom-user-page-id' );
				$redirect_to = ! empty( $new_page_id ) ? \get_permalink( $new_page_id ) : \get_home_url();
				$link_markup = '<a href="' . \esc_url( \wp_login_url( $redirect_to ) ) . '">' . \esc_html__( 'Login here.', 'wp-2fa' ) . '</a>';
				$message     = '<p id="wp_2fa_login_to_view_text">' . str_replace( '{login_url}', $link_markup, WP2FA::get_wp2fa_white_label_setting( 'login-to-view-area', true ) ) . '</p>';
				echo \wp_kses_post( $message );
				$content = ob_get_contents();
				ob_end_clean();
				return $content;
			}
		}

		/**
		 * Output setup nag.
		 *
		 * @param array $atts - Array with the attributes passed to shortcode.
		 *
		 * @return string
		 */
		public static function user_setup_2fa_notice( $atts ) {
			$atts = \shortcode_atts(
				array(
					'configure_2fa_url' => '',
				),
				$atts
			);

			$configure_2fa_url = \esc_url_raw( $atts['configure_2fa_url'] );

			// TODO: is that really necessary?
			User_Notices::init();

			if ( ! is_admin() && is_user_logged_in() ) {
				\wp_enqueue_script( 'wp_2fa_micro_modals' );
				\wp_enqueue_script( 'wp_2fa_frontend_scripts' );
				\wp_enqueue_style( 'wp_2fa_styles' );

				$data_array = array(
					'ajaxURL'        => \admin_url( 'admin-ajax.php' ),
					'roles'          => WP_Helper::get_roles_wp(),
					'nonce'          => \wp_create_nonce( 'wp-2fa-settings-nonce' ),
					'codesPreamble'  => \esc_html__( 'These are the 2FA backup codes for the user', 'wp-2fa' ),
					'readyText'      => \esc_html__( 'I\'m ready', 'wp-2fa' ),
					'codeReSentText' => \esc_html__( 'New code sent', 'wp-2fa' ),
					'allDoneHeading' => \esc_html__( 'All done.', 'wp-2fa' ),
					'allDoneText'    => \esc_html__( 'Your login just got more secure.', 'wp-2fa' ),
					'closeWizard'    => \esc_html__( 'Close Wizard', 'wp-2fa' ),
					'redirectToUrl'  => $configure_2fa_url,
				);
				\wp_localize_script( 'wp_2fa_frontend_scripts', 'wp2faData', $data_array );

				ob_start();
				User_Notices::user_setup_2fa_nag( 'output_shortcode', $configure_2fa_url );
				$content = ob_get_contents();
				ob_end_clean();

				return $content;
			}

			return '';
		}

		/**
		 * Output the style of the nags on FE pages.
		 *
		 * @return string
		 *
		 * @since 4.0.0
		 */
		public static function get_notification_style(): string {
			$styles = <<<CSS
			<style media="screen">
			.wp-2fa-shortcode-wrapper .wp-2fa-nag, .woocommerce .wp-2fa-nag {
				width: 100%;
				border: 1px solid #eee;
				border-left: 3px solid red;
				padding: 12px 15px;
				margin-bottom: 20px;
				font-size: 13px;
			}
			.wp-2fa-shortcode-wrapper .wp-2fa-nag p, .woocommerce .wp-2fa-nag p {
				margin-bottom: 5px
			}
			.wp-2fa-shortcode-wrapper .wp-2fa-nag br + span, .woocommerce .wp-2fa-nag br + span {
				clear: both;
				display: block;
				margin-top: 10px;
				margin-bottom: 10px;
			}
			.wp-2fa-shortcode-wrapper .wp-2fa-nag a.button, .woocommerce .wp-2fa-nag a.button {
				font-size: 13px;
				padding: 0 !important;
				margin-right: 20px;
				background-color: transparent;
			}
			.wp-2fa-shortcode-wrapper .wp-2fa-nag a.button:visited, .woocommerce .wp-2fa-nag a.button:visited {
				color: #222;
			}
			</style>
			CSS;

			return $styles;
		}
	}
}
