<?php
/**
 * Load Conversational Form related functionalities.
 *
 * @since 1.4.0
 * @package sureforms-pro
 */

namespace SRFM_Pro\Inc\Pro;

use SRFM\Inc\Generate_Form_Markup;
use SRFM\Inc\Helper;
use SRFM\Inc\Payments\Stripe\Stripe_Helper;
use SRFM_Pro\Inc\Helper as Pro_Helper;
use SRFM_Pro\Inc\Traits\Get_Instance;

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

/**
 * Load Conversational Form related functionalities.
 *
 * @since 1.4.0
 */
class Conversational_Form {
	use Get_Instance;

	/**
	 * Flag to determine whether to check block content before rendering.
	 *
	 * If true, empty block content will not be rendered in the conversational form,
	 * preventing empty blocks from appearing in the output.
	 *
	 * @since 2.3.0
	 * @var bool
	 */
	protected static $check_empty_block_before_render = false;

	/**
	 * Conversational Form data.
	 *
	 * @var array<string,mixed>
	 * @since 1.4.0
	 */
	private static $conversational_form_data = [];

	/**
	 * Live mode data.
	 *
	 * @var array<string,mixed>
	 * @since 1.4.0
	 */
	private static $srfm_live_mode_data = [];

	/**
	 * Constructor.
	 *
	 * @since 1.4.0
	 * @return void
	 */
	public function __construct() {
		$this->load_admin_assets();
		add_action( 'template_redirect', [ $this, 'load_conversational_form_frontend' ] );
	}

	/**
	 * Load conversational form frontend assets.
	 *
	 * @since 1.4.0
	 * @return void
	 */
	public function load_conversational_form_frontend() {
		global $post;
		// Set the live mode data and conversational form data.
		self::$srfm_live_mode_data      = empty( self::$srfm_live_mode_data ) ? Helper::get_instant_form_live_data() : self::$srfm_live_mode_data;
		self::$conversational_form_data = empty( self::$conversational_form_data ) ? $this->get_conversational_form_data() : self::$conversational_form_data;

		// if the request is coming from a preview from form block then return the default value.
		$srfm_form_preview = isset( $_GET['form_preview'] ) ? boolval( sanitize_text_field( wp_unslash( $_GET['form_preview'] ) ) ) : false;  // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		// Only load the conversational form frontend assets on the instant form page.
		if ( ! $srfm_form_preview && ! empty( $post->post_type ) && SRFM_FORMS_POST_TYPE === $post->post_type ) {
			$this->load_frontend_assets();
		}
	}

	/**
	 * Initialize Conversational Form frontend related functionalities.
	 *
	 * @since 1.4.0
	 * @return void
	 */
	public function load_frontend_assets() {
		add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
		add_filter( 'srfm_use_color_or_image_as_bg', [ $this, 'is_conversational_form_deactivated' ] );
		add_filter( 'srfm_add_background_classes', [ $this, 'restrict_background_classes' ] );
		add_filter( 'srfm_use_custom_body_template', [ $this, 'is_conversational_form_active' ] );
		add_action( 'srfm_after_instant_form_body', [ $this, 'load_conversational_form' ], 10, 3 );
		add_filter( 'srfm_use_page_break_layout', [ $this, 'is_conversational_form_deactivated' ] );
		add_filter( 'srfm_use_custom_field_content', [ $this, 'is_conversational_form_active' ] );
		add_action( 'srfm_after_field_content', [ $this, 'load_conversational_markup' ], 10, 2 );
		add_filter( 'srfm_css_vars_sizes', [ $this, 'cf_spacing_variables' ] );
		add_filter( 'srfm_is_inline_button', [ $this, 'is_inline_button' ] );
		add_action( 'srfm_form_css_variables', [ $this, 'add_custom_cf_variables' ] );
	}

	/**
	 * Initialize Conversational Form backend related functionalities.
	 *
	 * @since 1.4.0
	 * @return void
	 */
	public function load_admin_assets() {
		add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_block_editor_scripts' ] );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
		add_action( 'srfm_register_additional_post_meta', [ $this, 'register_conversational_form_post_meta' ] );
		add_filter( 'srfm_modify_ai_post_metas', [ $this, 'create_metas_for_ai' ], 10, 2 );
		add_filter( 'srfm_ai_form_generator_body', [ $this, 'add_conversational_form_version' ], 10, 2 );
		add_filter( 'srfm_ai_field_map_skip_fields', [ $this, 'skip_fields_in_ai_builder' ], 10, 2 );
		add_filter( 'srfm_ai_field_modify_field_type', [ $this, 'field_modify_field_type' ], 10, 3 );
	}

	/**
	 * Modify field type for Conversational Form.
	 * In case of dropdown field type, if the number of options is less than or equal to 6, then change the field type to multi-choice.
	 *
	 * @param string              $field_type The field type.
	 * @param array<string,mixed> $field_data The field data.
	 * @param bool                $is_conversational The Conversational Form status.
	 *
	 * @since 1.4.0
	 * @return string
	 */
	public function field_modify_field_type( $field_type, $field_data, $is_conversational ) {
		if ( empty( $is_conversational ) ) {
			return $field_type;
		}

		if ( 'dropdown' === $field_type && is_array( $field_data['fieldOptions'] ) && 6 >= count( $field_data['fieldOptions'] ) ) {
			$field_type = 'multi-choice';
		}

		return $field_type;
	}

	/**
	 * Skip fields in AI builder.
	 *
	 * @param array<string,mixed> $skip_fields The skip fields.
	 * @param bool                $is_conversational The Conversational Form status.
	 *
	 * @since 1.4.0
	 * @return array<string|mixed>
	 */
	public function skip_fields_in_ai_builder( $skip_fields, $is_conversational ) {

		if ( empty( $is_conversational ) ) {
			return $skip_fields;
		}

		return [
			'checkbox',
			'gdpr',
		];
	}

	/**
	 * Add conversational form version to the AI form generator body.
	 *
	 * @param array<string,mixed> $body The body.
	 * @param array<string,mixed> $params The params.
	 *
	 * @since 1.4.0
	 * @return array<string,mixed>
	 */
	public function add_conversational_form_version( $body, $params ) {

		if ( ! is_array( $params ) || ! isset( $params['is_conversional'] ) || ! $params['is_conversional'] ) {
			return $body;
		}

		return array_merge(
			$body,
			[
				'version' => 'conversational',
			]
		);
	}

	/**
	 * Create metas for AI when form type is Conversational.
	 *
	 * @param array<string,mixed> $metas The metas.
	 * @param array<string,mixed> $form_info_obj The form info object.
	 *
	 * @since 1.4.0
	 * @return array<string,mixed>
	 */
	public function create_metas_for_ai( $metas, $form_info_obj ) {

		if ( ! is_object( $form_info_obj ) || ! $form_info_obj->is_conversational ) {
			return $metas;
		}

		$_srfm_premium_common = isset( $form_info_obj->template_metas ) && isset( $form_info_obj->template_metas->_srfm_premium_common ) ? (array) $form_info_obj->template_metas->_srfm_premium_common : [];

		// if any of the meta is not set then set the default value.
		if ( empty( $_srfm_premium_common['welcome_screen_heading'] ) ) {
			$_srfm_premium_common['welcome_screen_heading'] = __( 'Help Us Gather Valuable Insights!', 'sureforms-pro' );
		}
		if ( empty( $_srfm_premium_common['welcome_screen_message'] ) ) {
			$_srfm_premium_common['welcome_screen_message'] = __( 'Answer a few quick questions to share your thoughts and make your voice heard.', 'sureforms-pro' );
		}
		if ( empty( $_srfm_premium_common['start_btn_text'] ) ) {
			$_srfm_premium_common['start_btn_text'] = __( 'Get Started', 'sureforms-pro' );
		}

		return [
			'_srfm_premium_common'        => [
				'is_welcome_screen' => true,
				...$_srfm_premium_common,
			],
			'_srfm_conversational_form'   => [
				'is_cf_enabled'      => true,
				'cf_layout'          => 'no-image',
				'cf_is_progress_bar' => true,
			],
			'_srfm_instant_form_settings' => [
				'bg_type'                       => 'color',
				'bg_color'                      => '#ffffff',
				'bg_image'                      => '',
				'site_logo'                     => '',
				'cover_type'                    => 'color',
				'cover_color'                   => '#111C44',
				'cover_image'                   => '',
				'enable_instant_form'           => true,
				'form_container_width'          => 620,
				'single_page_form_title'        => true,
				'use_banner_as_page_background' => false,
			],
		];
	}

	/**
	 * Disable inline button for Conversational Form.
	 *
	 * @param bool $value The default value.
	 *
	 * @since 1.4.0
	 * @return bool
	 */
	public function is_inline_button( $value ) {
		$is_conversational_form_active = $this->is_conversational_form_active( $value );
		return $is_conversational_form_active ? false : $value;
	}

	/**
	 * Load Welcome Screen.
	 *
	 * @param \WP_Post $post The post object.
	 * @param int      $id The post ID.
	 *
	 * @since 1.4.0
	 * @return void
	 */
	public function load_conversational_markup( $post, $id ) {
		if ( $this->is_conversational_form_deactivated() ) {
			return;
		}

		$welcome_screen    = ! empty( self::$srfm_live_mode_data ) ? self::$srfm_live_mode_data : Helper::get_array_value( get_post_meta( $id, '_srfm_premium_common', true ) );
		$is_welcome_screen = is_array( $welcome_screen ) && isset( $welcome_screen['is_welcome_screen'] ) && $welcome_screen['is_welcome_screen'] ? Helper::get_string_value( $welcome_screen['is_welcome_screen'] ) : false;
		$start_btn_text    = '';

		// get layout data.
		$conversational_form_data = $this->get_conversational_form_data();
		$cf_layout                = is_array( $conversational_form_data ) && isset( $conversational_form_data['cf_layout'] ) ? Helper::get_string_value( $conversational_form_data['cf_layout'] ) : 'image-on-right';

		if ( $is_welcome_screen ) {
			$welcome_screen_heading = is_array( $welcome_screen ) && isset( $welcome_screen['welcome_screen_heading'] ) && $welcome_screen['welcome_screen_heading'] ? Helper::get_string_value( $welcome_screen['welcome_screen_heading'] ) : '';
			$welcome_screen_message = is_array( $welcome_screen ) && isset( $welcome_screen['welcome_screen_message'] ) && $welcome_screen['welcome_screen_message'] ? Helper::get_string_value( $welcome_screen['welcome_screen_message'] ) : '';
			$welcome_screen_image   = is_array( $welcome_screen ) && isset( $welcome_screen['welcome_screen_image'] ) && $welcome_screen['welcome_screen_image'] ? Helper::get_string_value( $welcome_screen['welcome_screen_image'] ) : '';
			$start_btn_text         = is_array( $welcome_screen ) && isset( $welcome_screen['start_btn_text'] ) && $welcome_screen['start_btn_text'] ? Helper::get_string_value( $welcome_screen['start_btn_text'] ) : '';

			ob_start();
			?>
				<div class="srfm-cf-welcome-screen">
					<?php if ( $welcome_screen_image ) { ?>
						<div class="<?php echo esc_attr( Helper::join_strings( [ 'srfm-cf-welcome-image-ctn', 'no-image' === $cf_layout ? 'srfm-no-image-layout' : '' ] ) ); ?>">
							<img src="<?php echo esc_url( $welcome_screen_image ); ?>" alt="<?php esc_attr_e( 'Welcome Screen Image', 'sureforms-pro' ); ?>" class="srfm-cf-welcome-image">
						</div>
					<?php } ?>
					<h2 class="srfm-cf-welcome-heading" style="<?php echo 'no-image' === $cf_layout ? esc_attr( 'text-align:center;' ) : ''; ?>"><?php echo esc_html( wp_strip_all_tags( $welcome_screen_heading ) ); ?></h2>
					<p class="srfm-cf-welcome-message" style="<?php echo 'no-image' === $cf_layout ? esc_attr( 'text-align:center;' ) : ''; ?>"><?php echo esc_html( wp_strip_all_tags( $welcome_screen_message ) ); ?></p>
				</div>
			<?php
		}

		$content     = $post->post_content;
		$pattern     = '/(-->\s*)/';
		$replacement = '$1<!-- wp:srfm/cf-break /-->';
		$content     = preg_replace( $pattern, $replacement, $content );

		if ( ! $content ) {
			return;
		}

		$blocks = explode( '<!-- wp:srfm/cf-break /-->', $content );

		// remove empty blocks.
		$blocks = array_filter( $blocks );

		if ( $is_welcome_screen ) {
			$welcome_screen = ob_get_clean();
			$blocks         = array_merge( [ $welcome_screen ], $blocks );
		}

		$new_content  = '';
		$j            = 0; // Initialize a manual index for the loop.
		$block_length = count( $blocks );

		for ( $i = 0; $i < $block_length; $i++ ) {
			if ( self::$check_empty_block_before_render ) {
				self::$check_empty_block_before_render = false;
			}

			$block = $blocks[ $i ];
			// Skip empty block and the closing register block.
			if ( ! $block || strpos( $block, '/wp:srfm/register' ) !== false ) {
				continue;
			}

			$is_block = has_blocks( $block );

			if ( $is_block ) {
				$parsed_blocks = parse_blocks( $block );
				$block_name    = $parsed_blocks[0]['blockName'] ?? '';
				/**
				 * Skip rendering if block visibility is set to false.
				 * Introduced with WP 6.9
				 *
				 * @since 2.1.0
				 */
				$is_block_visible = $parsed_blocks[0]['attrs']['metadata']['blockVisibility'] ?? true;
				if ( ! $is_block_visible ) {
					continue;
				}

				switch ( $block_name ) {
					case 'srfm/hidden':
						$new_content .= do_blocks( $block );
						continue 2; // Skip wrapping for hidden blocks.
					case 'srfm/page-break':
					case 'srfm/inline-button':
					case 'srfm/separator':
					case 'srfm/register':
						continue 2; // Skip rendering for page-break, inline-button, separator, register blocks.
					case 'srfm/address':
						$address_content = $block;
						for ( $j = $i + 1; $j < $block_length; $j++ ) {
							$next_block = $blocks[ $j ];
							if ( ! $next_block ) {
								continue;
							}

							$next_parsed_blocks    = parse_blocks( $next_block );
							$next_block_inner_html = $next_parsed_blocks[0]['innerHTML'] ?? '';

							$address_content .= $next_block;
							unset( $blocks[ $j ] ); // Remove the processed block.

							if ( strpos( $next_block_inner_html, '/wp:srfm/address' ) !== false ) {
								break; // End processing when the closing address block is reached.
							}
						}

						// shift the keys of the blocks array to correct the index.
						$blocks       = array_values( $blocks );
						$block_length = count( $blocks );

						// Add the markup for address block.
						$new_content .= $this->render_single_conversational_block( $i, $block_length, $address_content, $is_block );
						continue 2; // Skip further processing for address-related blocks.
					case 'srfm/login':
						$login_content = $block;

						for ( $j = $i + 1; $j < $block_length; $j++ ) {
							$next_block = $blocks[ $j ];
							if ( ! $next_block ) {
								continue;
							}

							$next_parsed_blocks    = parse_blocks( $next_block );
							$next_block_inner_html = $next_parsed_blocks[0]['innerHTML'] ?? '';

							$login_content .= $next_block;
							unset( $blocks[ $j ] ); // Remove the processed block.

							if ( strpos( $next_block_inner_html, '/wp:srfm/login' ) !== false ) {
								break; // End processing when the closing login block is reached.
							}
						}

						// Reindex the blocks array after unsetting.
						$blocks       = array_values( $blocks );
						$block_length = count( $blocks );

						// Add the markup for login block.
						$new_content .= $this->render_single_conversational_block( $i, $block_length, $login_content, $is_block );
						continue 2; // Skip further processing for login-related blocks.
					case 'srfm/repeater':
						$repeater_result = $this->process_group_block(
							[
								'blocks'       => is_array( $blocks ) ? $blocks : [],
								'i'            => (int) $i,
								'block_length' => (int) $block_length,
								'block'        => (string) $block,
								'is_block'     => (bool) $is_block,
								'group_name'   => 'repeater',
							]
						);
						$blocks          = is_array( $repeater_result['blocks'] ) ? $repeater_result['blocks'] : [];
						$block_length    = (int) $repeater_result['block_length'];
						$new_content    .= (string) $repeater_result['group_template'];
						continue 2; // Skip further processing for repeater-related blocks.
					case 'srfm/payment':
						// Check if payment gateway is configured.
						$is_payment_configured = $this->verify_payment_is_configured( $parsed_blocks[0] );

						// Skip payment block if no payment gateway is configured.
						if ( ! $is_payment_configured ) {
							continue 2;
						}

						self::$check_empty_block_before_render = true;

						// Payment is configured, render the block.
						$new_content .= $this->render_single_conversational_block( $i, $block_length, $block, $is_block );
						continue 2;
					default:
						$new_content .= $this->render_single_conversational_block( $i, $block_length, $block, $is_block );
				}
			} else {
				// Render the welcome screen and the start button (if applicable).
				$new_content .= $this->render_single_conversational_block( $i, $block_length, $block, $is_block, $start_btn_text );
			}
		}

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Need it to render Conversational Form content.
		echo $new_content;
		echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}

	/**
	 * Register conversational form post meta.
	 *
	 * @since 1.4.0
	 * @return void
	 */
	public static function register_conversational_form_post_meta() {
		register_post_meta(
			SRFM_FORMS_POST_TYPE,
			'_srfm_conversational_form',
			[
				'single'        => true,
				'type'          => 'object',
				'auth_callback' => static function() {
					return Helper::current_user_can();
				},
				'show_in_rest'  => [
					'schema' => [
						'type'       => 'object',
						'context'    => [ 'edit' ],
						'properties' => [
							'is_cf_enabled'             => [
								'type' => 'boolean',
							],
							'cf_layout'                 => [
								'type' => 'string',
							],
							'cf_is_progress_bar'        => [
								'type' => 'boolean',
							],
							'cf_label_size'             => [
								'type' => 'number',
							],
							'cf_label_size_unit'        => [
								'type' => 'string',
							],
							'cf_label_line_height'      => [
								'type' => 'number',
							],
							'cf_label_line_height_unit' => [
								'type' => 'string',
							],
							'cf_help_text_size'         => [
								'type' => 'number',
							],
							'cf_help_text_size_unit'    => [
								'type' => 'string',
							],
							'cf_help_text_line_height'  => [
								'type' => 'number',
							],
							'cf_help_text_line_height_unit' => [
								'type' => 'string',
							],
						],
					],
				],
				'default'       => [
					'is_cf_enabled'                 => false,
					'cf_layout'                     => 'image-on-right',
					'cf_is_progress_bar'            => false,
					'cf_label_size'                 => 24,
					'cf_label_size_unit'            => 'px',
					'cf_label_line_height'          => 1.4,
					'cf_label_line_height_unit'     => 'em',
					'cf_help_text_size'             => 16,
					'cf_help_text_size_unit'        => 'px',
					'cf_help_text_line_height'      => 1.4,
					'cf_help_text_line_height_unit' => 'em',
				],
			]
		);
	}

	/**
	 * Get Conversational Form data.
	 *
	 * @since 1.4.0
	 * @return array<string,mixed>
	 */
	public function get_conversational_form_data() {
		return ! empty( self::$srfm_live_mode_data ) ? self::$srfm_live_mode_data : Helper::get_array_value( get_post_meta( Helper::get_integer_value( get_the_ID() ), '_srfm_conversational_form', true ) );
	}

	/**
	 * Check if Conversational Form is enabled.
	 *
	 * @param bool $value The default value.
	 *
	 * @since 1.4.0
	 * @return bool
	 */
	public function is_conversational_form_active( $value ) {
		$conversational_form = ! empty( self::$conversational_form_data ) && is_array( self::$conversational_form_data ) ? self::$conversational_form_data : $this->get_conversational_form_data();
		return is_array( $conversational_form ) && isset( $conversational_form['is_cf_enabled'] ) ? filter_var( $conversational_form['is_cf_enabled'], FILTER_VALIDATE_BOOLEAN ) : $value;
	}

	/**
	 * Check if Conversational Form is disabled.
	 *
	 * @param bool $value The default value is true.
	 *
	 * @since 1.4.0
	 * @return bool
	 */
	public function is_conversational_form_deactivated( $value = true ) {
		return ! $this->is_conversational_form_active( $value );
	}

	/**
	 * Load Conversational Form.
	 *
	 * @param int                 $srfm_custom_post_id The SureForm custom post ID.
	 * @param array<string,mixed> $instant_form_settings The Instant Form settings.
	 * @param string              $body_classes The body classes.
	 *
	 * @since 1.4.0
	 * @return void
	 */
	public function load_conversational_form( $srfm_custom_post_id, $instant_form_settings, $body_classes ) {

		if ( $this->is_conversational_form_deactivated() ) {
			return;
		}

		$cf_layout = ! empty( self::$conversational_form_data ) && is_array( self::$conversational_form_data ) && isset( self::$conversational_form_data['cf_layout'] ) ? Helper::get_string_value( self::$conversational_form_data['cf_layout'] ) : 'image-on-right';

		$site_logo     = isset( $instant_form_settings['site_logo'] ) && $instant_form_settings['site_logo'] ? Helper::get_string_value( $instant_form_settings['site_logo'] ) : '';
		$page_bg_image = isset( $instant_form_settings['bg_image'] ) && $instant_form_settings['bg_image'] ? Helper::get_string_value( $instant_form_settings['bg_image'] ) : ''; // This is the page background image which will be added in the conversational form image on left and right layouts.
		if ( ! empty( $page_bg_image ) && ! filter_var( $page_bg_image, FILTER_VALIDATE_URL ) ) {
			$page_bg_image = ''; // Reset to an empty string if not a valid URL.
		}
		$progress_bar = is_array( self::$conversational_form_data ) && isset( self::$conversational_form_data['cf_is_progress_bar'] ) && self::$conversational_form_data['cf_is_progress_bar'] ? Helper::get_string_value( self::$conversational_form_data['cf_is_progress_bar'] ) : false;
		$container_id = 'srfm-form-container-' . Helper::get_string_value( $srfm_custom_post_id );
		$form_styling = Helper::get_array_value( get_post_meta( $srfm_custom_post_id, '_srfm_forms_styling', true ) );
		$bg_type      = isset( $form_styling['bg_type'] ) && $form_styling['bg_type'] ? Helper::get_string_value( $form_styling['bg_type'] ) : 'color';
		$bg_image     = isset( $form_styling['bg_image'] ) && $form_styling['bg_image'] ? Helper::get_string_value( $form_styling['bg_image'] ) : '';

		if ( ! empty( $bg_image ) && ! filter_var( $bg_image, FILTER_VALIDATE_URL ) ) {
			$bg_image = ''; // Reset to an empty string if it is not a valid URL.
		}
		$overlay_type       = $form_styling['bg_gradient_overlay_type'] ?? '';
		$background_classes = Helper::get_background_classes( $bg_type, $overlay_type, $bg_image );

		$is_live_mode = ! empty( self::$srfm_live_mode_data ) && is_array( self::$srfm_live_mode_data ) && isset( self::$srfm_live_mode_data['live_mode'] ) ? Helper::get_string_value( self::$srfm_live_mode_data['live_mode'] ) : 'false';

		// Add the custom styling class if form theme is set to custom.
		$form_styling_starter = Helper::get_array_value( get_post_meta( Helper::get_integer_value( $srfm_custom_post_id ), '_srfm_forms_styling_starter', true ) );
		$form_theme           = isset( $form_styling_starter['form_theme'] ) ? Helper::get_string_value( $form_styling_starter['form_theme'] ) : 'default';
		if ( 'custom' === $form_theme ) {
			$background_classes .= ' srfm-custom-stylings';
		}

		ob_start();
		?>
			<body <?php body_class( $body_classes ); ?> data-live-mode="<?php echo esc_attr( $is_live_mode ); ?>">
				<div class="srfm-form-wrapper srfm-cf-ctn" id="srfm-single-page-container">
					<div class="srfm-cf-wrap">
						<!-- Left Image -->
						<?php if ( 'image-on-left' === $cf_layout ) { ?>
							<div class="srfm-cf-bg-image">
								<?php if ( ! empty( $page_bg_image ) ) { ?>
									<img src="<?php echo esc_url( $page_bg_image ); ?>" alt="<?php esc_attr_e( 'Conversational Form Background', 'sureforms-pro' ); ?>">
								<?php } ?>
							</div>
						<?php } ?>

						<div class="srfm-cf-content-ctn">
							<!-- Content -->
							<div class="<?php echo esc_attr( Helper::join_strings( [ 'srfm-cf-inner-ctn', 'srfm-form-container', $container_id, $background_classes ] ) ); ?>">
								<!-- Logo -->
								<?php if ( $site_logo ) { ?>
									<div class="srfm-cf-site-logo" style="<?php echo 'no-image' === $cf_layout ? esc_attr( 'align-self:center;' ) : ''; ?>">
										<a href="<?php echo esc_url( home_url() ); ?>" aria-label="<?php esc_attr_e( 'Link to homepage', 'sureforms-pro' ); ?>">
											<img src="<?php echo esc_url( $site_logo ); ?>" alt="<?php esc_attr_e( 'Site Logo', 'sureforms-pro' ); ?>">
										</a>
									</div>
								<?php } ?>
								<div class="srfm-cf-content">

									<!-- Form -->
									<?php
										// All the necessary escaping is done in the Generate_Form_Markup class.
										echo Generate_Form_Markup::get_form_markup( $srfm_custom_post_id, false, 'sureforms_form' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

										/**
										 * WordPress 6.9+ compatibility: Print late-enqueued block styles.
										 * In WP 6.9, the template output buffer hoists styles to <head>, but conversational
										 * forms use a custom body template that bypasses this mechanism. We manually print
										 * styles here to ensure pro block styles are output correctly.
										 *
										 * @since 2.1.0
										 */
										global $wp_version;
									if ( version_compare( $wp_version, '6.9', '>=' ) ) {
										wp_print_styles();
									}
									?>

								</div>
								<?php if ( apply_filters( 'srfm_show_conversational_form_footer', true ) ) { ?>
								<div class="srfm-cf-progress-bar-ctn">
									<?php $custom_styling_btn_classes = implode( ' ', array_diff( explode( ' ', Helper::get_string_value( self::$conversational_form_data['btn_classes'] ?? '' ) ), [ 'srfm-button', 'srfm-cf-btn' ] ) ); ?>
									<div class="srfm-cf-nav-btn-ctn">
										<button class="srfm-cf-prev-btn <?php echo esc_attr( $custom_styling_btn_classes ); ?>">
											<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
												<path d="M10 12L6 8L10 4" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
											</svg>
										</button>
										<button class="srfm-cf-next-btn <?php echo esc_attr( $custom_styling_btn_classes ); ?>">
											<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
												<path d="M6 12L10 8L6 4" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
											</svg>
										</button>
									</div>
									<?php if ( $progress_bar ) { ?>
										<div class="srfm-cf-progress-bar">
											<div class="srfm-cf-progress-bar-fill"></div>
											<div class="srfm-cf-progress-bar-percentage"></div>
										</div>
									<?php } ?>
								</div>
								<?php } ?>
							</div>
						</div>

						<!-- Right Image -->
						<?php if ( 'image-on-right' === $cf_layout ) { ?>
							<div  class="srfm-cf-bg-image">
								<?php if ( ! empty( $page_bg_image ) ) { ?>
									<img src="<?php echo esc_url( $page_bg_image ); ?>" alt="<?php esc_attr_e( 'Conversational Form Background', 'sureforms-pro' ); ?>">
								<?php } ?>
							</div>
						<?php } ?>
					</div>
				</div>
				<?php
					wp_footer();
				?>
			</body>
		<?php
		// All the necessary escaping is already done.
		echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}

	/**
	 * Enqueue conversational form block editor scripts.
	 *
	 * @return void
	 * @since 1.4.0
	 */
	public function enqueue_block_editor_scripts() {
		$scripts = [
			[
				'unique_file'        => 'srfmConversationalForms',
				'unique_handle'      => 'conversational-form',
				'extra_dependencies' => [],
			],
		];
		$this->enqueue_scripts( $scripts );
	}

	/**
	 * Enqueue conversational form admin scripts.
	 *
	 * @return void
	 * @since 1.4.0
	 */
	public function enqueue_admin_scripts() {
		$scripts = [
			[
				'unique_file'        => 'srfmConversationalFormAdmin',
				'unique_handle'      => 'conversational-form-admin',
				'extra_dependencies' => [],
			],
		];
		$this->enqueue_scripts( $scripts );
	}

	/**
	 * Enqueue required css for the Conversational Form frontend.
	 *
	 * @since 1.4.0
	 * @return void
	 */
	public function enqueue_assets() {
		if ( $this->is_conversational_form_deactivated() ) {
			return;
		}

		$file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
		$dir_name    = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
		$css_uri     = SRFM_PRO_URL . 'assets/css/' . $dir_name . '/package/pro/';
		// This checks the text direction of the site, if it is RTL then it will load the RTL version of the CSS file.
		$rtl = is_rtl() ? '-rtl' : '';

		// Load the frontend custom app styles.
		wp_enqueue_style( SRFM_PRO_SLUG . '-conversational-form', $css_uri . 'conversational-form' . $file_prefix . $rtl . '.css', [], SRFM_PRO_VER );

		$styles = 'body { overflow: hidden; } @media (max-width: 767px) { body { overflow: auto; } .srfm-cf-content-ctn { overflow-y: visible; } }';
			wp_add_inline_style( SRFM_PRO_SLUG . '-conversational-form', $styles );

		$scripts = [
			[
				'unique_file'        => 'srfmConversationalFormFrontend',
				'unique_handle'      => 'conversational-form-frontend',
				'extra_dependencies' => [],
			],
		];

		foreach ( $scripts as $script ) {

			$script_dep_path = SRFM_PRO_DIR . 'dist/package/pro/' . $script['unique_file'] . '.asset.php';
			$script_dep_data = file_exists( $script_dep_path )
				? include $script_dep_path
				: [
					'dependencies' => [],
					'version'      => SRFM_PRO_VER,
				];
			$script_dep      = array_merge( $script_dep_data['dependencies'], $script['extra_dependencies'] );

			// Scripts.
			wp_enqueue_script(
				SRFM_PRO_SLUG . '-' . $script['unique_handle'], // Handle.
				SRFM_PRO_URL . 'dist/package/pro/' . $script['unique_file'] . '.js',
				$script_dep, // Dependencies, defined above.
				$script_dep_data['version'], // SRFM_VER.
				true // Enqueue the script in the footer.
			);

			// Register script translations.
			Pro_Helper::register_script_translations( SRFM_PRO_SLUG . '-' . $script['unique_handle'] );

		}
	}

	/**
	 * Replace the spacing variables with values for the Conversational Form.
	 * This is used in the frontend.
	 *
	 * @hooked - srfm_css_vars_sizes
	 *
	 * @param array<string|mixed> $sizes array of css variables coming from 'srfm_css_vars_sizes' filter.
	 * @since 1.4.0
	 * @return array<string|mixed>
	 */
	public function cf_spacing_variables( $sizes ) {
		// Do not update the variables if the form is not a conversational form or if it is the admin page.
		if ( $this->is_conversational_form_deactivated() || is_admin() ) {
			return $sizes;
		}
		$cf_spacing_vars = [
			'small'  => [
				'--srfm-row-gap-between-blocks'           => '20px',
				// Label Variables.
				'--srfm-label-font-size'                  => '20px',
				'--srfm-label-line-height'                => '30px',
				'--srfm-label-font-weight'                => '600',
				// Description Variables.
				'--srfm-description-font-size'            => '14px',
				'--srfm-description-line-height'          => '18px',
				'--srfm-description-margin-top'           => '6px',
				// Error Variables.
				'--srfm-error-font-size'                  => '14px',
				'--srfm-error-line-height'                => '20px',
				// Input Margin.
				'--srfm-input-field-margin-top'           => '20px',
				'--srfm-input-field-margin-bottom'        => '4px',
				// Multichoice Margin.
				'--srfm-multi-choice-outer-padding'       => '20px 0 4px',
				// Checkbox & GDPR Variables.
				'--srfm-checkbox-label-font-size'         => '16px',
				'--srfm-checkbox-label-line-height'       => '24px',
				'--srfm-checkbox-label-font-weight'       => '500',
				'--srfm-checkbox-description-font-size'   => '14px',
				'--srfm-checkbox-description-line-height' => '20px',
				'--srfm-check-ctn-width'                  => '20px',
				'--srfm-check-ctn-height'                 => '20px',
				'--srfm-checkbox-description-margin-left' => '28px',
				'--srfm-checkbox-margin-top-frontend'     => '5px',
				'--srfm-check-svg-top'                    => '3px',
				'--srfm-check-svg-left'                   => '3px',
				'--srfm-check-svg-size'                   => '12px',
				// Address Block Variables for Conversational Layout.
				'--srfm-address-label-font-size'          => '14px',
				'--srfm-address-label-line-height'        => '20px',
				'--srfm-address-description-font-size'    => '12px',
				'--srfm-address-description-line-height'  => '16px',
				'--srfm-address-input-margin'             => '4px 0',
			],
			'medium' => [
				'--srfm-row-gap-between-blocks'           => '24px',
				// Label Variables.
				'--srfm-label-font-size'                  => '24px',
				'--srfm-label-line-height'                => '32px',
				// Description Variables.
				'--srfm-description-font-size'            => '16px',
				'--srfm-description-line-height'          => '24px',
				'--srfm-description-margin-top'           => '8px',
				// Error Variables.
				'--srfm-error-font-size'                  => '16px',
				'--srfm-error-line-height'                => '24px',
				// Input Margin.
				'--srfm-input-field-margin-top'           => '24px',
				'--srfm-input-field-margin-bottom'        => '6px',
				// Multichoice Margin.
				'--srfm-multi-choice-outer-padding'       => '24px 0 6px',
				// Checkbox & GDPR Variables.
				'--srfm-checkbox-label-font-size'         => '18px',
				'--srfm-checkbox-label-line-height'       => '28px',
				'--srfm-checkbox-label-font-weight'       => '500',
				'--srfm-checkbox-description-font-size'   => '16px',
				'--srfm-checkbox-description-line-height' => '24px',
				'--srfm-check-ctn-width'                  => '24px',
				'--srfm-check-ctn-height'                 => '24px',
				'--srfm-checkbox-description-margin-left' => '32px',
				'--srfm-checkbox-margin-top-frontend'     => '5px',
				'--srfm-check-svg-top'                    => '4px',
				'--srfm-check-svg-left'                   => '4px',
				'--srfm-check-svg-size'                   => '14px',
				// Address Block Variables for Conversational Layout.
				'--srfm-address-label-font-size'          => '16px',
				'--srfm-address-label-line-height'        => '24px',
				'--srfm-address-description-font-size'    => '14px',
				'--srfm-address-description-line-height'  => '20px',
				'--srfm-address-input-margin'             => '6px 0',
			],
			'large'  => [
				'--srfm-row-gap-between-blocks'           => '28px',
				// Label Variables.
				'--srfm-label-font-size'                  => '28px',
				'--srfm-label-line-height'                => '34px',
				// Description Variables.
				'--srfm-description-font-size'            => '16px',
				'--srfm-description-line-height'          => '24px',
				'--srfm-description-margin-top'           => '8px',
				// Error Variables.
				'--srfm-error-font-size'                  => '16px',
				'--srfm-error-line-height'                => '24px',
				// Input Margin.
				'--srfm-input-field-margin-top'           => '28px',
				'--srfm-input-field-margin-bottom'        => '8px',
				// Multichoice Margin.
				'--srfm-multi-choice-outer-padding'       => '28px 0 8px',
				// Checkbox & GDPR Variables.
				'--srfm-checkbox-label-font-size'         => '20px',
				'--srfm-checkbox-label-line-height'       => '30px',
				'--srfm-checkbox-label-font-weight'       => '500',
				'--srfm-checkbox-description-font-size'   => '16px',
				'--srfm-checkbox-description-line-height' => '24px',
				'--srfm-check-ctn-width'                  => '28px',
				'--srfm-check-ctn-height'                 => '28px',
				'--srfm-checkbox-description-margin-left' => '38px',
				'--srfm-checkbox-margin-top-frontend'     => '7px',
				'--srfm-check-svg-top'                    => '5px',
				'--srfm-check-svg-left'                   => '5px',
				'--srfm-check-svg-size'                   => '16px',
				// Address Block Variables for Conversational Layout.
				'--srfm-address-label-font-size'          => '18px',
				'--srfm-address-label-line-height'        => '28px',
				'--srfm-address-description-font-size'    => '16px',
				'--srfm-address-description-line-height'  => '24px',
				'--srfm-address-input-margin'             => '8px 0',
			],
		];

		return array_replace_recursive( $sizes, $cf_spacing_vars );
	}

	/**
	 * Render single block with navigation button for conversational layout.
	 * This is used in the frontend.
	 *
	 * @param int    $index The index of the block.
	 * @param int    $total_blocks The total number of blocks.
	 * @param string $block The block content.
	 * @param bool   $is_block Whether it is a block or not.
	 * @param string $start_btn_text The text for the start button.
	 *
	 * @since 1.4.0
	 * @return string $output The rendered conversational block markup.
	 */
	public function render_single_conversational_block( $index, $total_blocks, $block, $is_block, $start_btn_text = '' ) {
		$block_content = do_blocks( $block );

		if ( self::$check_empty_block_before_render ) {
			// Trim block content to remove whitespace.
			$block_content = trim( $block_content );
			if ( empty( $block_content ) ) {
				return '';
			}
		}

		$output  = '';
		$output .= '<div class="srfm-cf-block">';
		$output .= $block_content;

		$output                                       .= '<div class="srfm-cf-btn-container">';
		$btn_classes                                   = implode( ' ', array_filter( apply_filters( 'srfm_add_button_classes', [ 'srfm-button', 'srfm-cf-btn' ] ) ) );
		self::$conversational_form_data['btn_classes'] = $btn_classes;

		if ( $is_block && $index < $total_blocks - 1 ) {
			$output .= sprintf(
				'<button class="%s srfm-cf-next-btn">%s</button>',
				esc_attr( $btn_classes ),
				esc_html__( 'Next', 'sureforms-pro' )
			);
			$output .= sprintf(
				/* translators: %1$s: opening wrapper tag for the text, %2$s: opening tag for the bold text, %3$s: closing tag for the bold text, %4$s: closing wrapper tag */
				esc_html__( '%1$sPress %2$sEnter%3$s%4$s', 'sureforms-pro' ),
				'<span class="srfm-cf-nav-helper-text">',
				'<span class="w-600">',
				'</span>',
				' &#9166;</span>',
			);
		} elseif ( $index === $total_blocks - 1 ) {
			// Final block doesn't need navigation buttons for non-address types.
			$output .= '';
		} else {

			$conversational_form_data = $this->get_conversational_form_data();

			$cf_layout = is_array( $conversational_form_data ) && isset( $conversational_form_data['cf_layout'] ) ? Helper::get_string_value( $conversational_form_data['cf_layout'] ) : 'image-on-right';

			$output .= sprintf(
				'<button class="%s srfm-cf-start-btn" style="%s">%s</button>',
				esc_attr( $btn_classes ),
				( 'no-image' === $cf_layout ? esc_attr( 'margin:auto;' ) : '' ),
				esc_html( wp_strip_all_tags( $start_btn_text ) )
			);
		}

		$output .= '</div></div>';
		return apply_filters(
			'srfm_single_conversational_block',
			$output,
			[
				'index'          => $index,
				'total_blocks'   => $total_blocks,
				'block'          => $block,
				'is_block'       => $is_block,
				'start_btn_text' => $start_btn_text,
				'btn_classes'    => $btn_classes,
			]
		);
	}

	/**
	 * Restrict adding the background classes if conversational form is deactivated.
	 *
	 * @param string $background_classes The background classes.
	 *
	 * @since 1.4.3
	 * @return string The background classes.
	 */
	public function restrict_background_classes( $background_classes ) {
		if ( ! $this->is_conversational_form_deactivated() ) {
			self::$conversational_form_data['custom_styling'] = strpos( $background_classes, 'srfm-custom-stylings' );
			if ( strpos( $background_classes, 'srfm-custom-stylings' ) !== false ) {
				return 'srfm-custom-stylings';
			}
			return '';
		}
		return $background_classes;
	}

	/**
	 * Add custom styling css variables for conversational forms.
	 * The font size and line height variables are being added for the conversational form label and description.
	 *
	 * @param array<string,string> $params array of values sent by action 'srfm_form_css_variables'.
	 * @since 1.6.3
	 * @return void
	 */
	public function add_custom_cf_variables( $params ) {
		unset( $params );
		if ( $this->is_conversational_form_deactivated() ) {
			return;
		}
		self::$conversational_form_data = empty( self::$conversational_form_data ) ? $this->get_conversational_form_data() : self::$conversational_form_data;

		$variables = [
			'--srfm-label-font-size'         => isset( self::$conversational_form_data['cf_label_size'] ) && isset( self::$conversational_form_data['cf_label_size_unit'] ) ? self::$conversational_form_data['cf_label_size'] . self::$conversational_form_data['cf_label_size_unit'] : '24px',
			'--srfm-label-line-height'       => isset( self::$conversational_form_data['cf_label_line_height'] ) && isset( self::$conversational_form_data['cf_label_line_height_unit'] ) ? self::$conversational_form_data['cf_label_line_height'] . self::$conversational_form_data['cf_label_line_height_unit'] : '1.4em',
			'--srfm-description-font-size'   => isset( self::$conversational_form_data['cf_help_text_size'] ) && isset( self::$conversational_form_data['cf_help_text_size_unit'] ) ? self::$conversational_form_data['cf_help_text_size'] . self::$conversational_form_data['cf_help_text_size_unit'] : '16px',
			'--srfm-description-line-height' => isset( self::$conversational_form_data['cf_help_text_line_height'] ) && isset( self::$conversational_form_data['cf_help_text_line_height_unit'] ) ? self::$conversational_form_data['cf_help_text_line_height'] . self::$conversational_form_data['cf_help_text_line_height_unit'] : '1.4em',
		];

		Pro_Helper::add_css_variables( $variables );
	}

	/**
	 * Verify if payment gateway is configured for a payment block.
	 *
	 * @param array<mixed> $parsed_block Parsed block data from parse_blocks().
	 * @since 2.3.0
	 * @return bool True if payment gateway is configured, false otherwise.
	 */
	private function verify_payment_is_configured( $parsed_block ) {
		// Check if Stripe is connected.
		$stripe_connected = Stripe_Helper::is_stripe_connected();

		/**
		 * Filter: srfm_payment_gateway_configured
		 *
		 * Check if any payment gateway is configured (Stripe, PayPal, etc.)
		 * This filter allows payment gateways to extend the configuration check.
		 *
		 * @param bool         $is_configured Whether any payment gateway is configured.
		 * @param array<mixed> $settings      Settings including block_data.
		 *
		 * @return bool True if any payment gateway is configured, false otherwise.
		 */
		return apply_filters(
			'srfm_payment_gateway_configured',
			$stripe_connected,
			[
				'block_data' => [
					'block_name'   => $parsed_block['blockName'],
					'parsed_block' => $parsed_block,
				],
			]
		);
	}

	/**
	 * Process a group block and its inner blocks for conversational form layout.
	 *
	 * This method handles processing of group blocks like repeater fields. It extracts all blocks
	 * between the opening and closing tags of the group block, processes them, and returns the
	 * updated blocks array along with the processed group content.
	 *
	 * @since 1.11.0
	 *
	 * @param array<string,mixed> $args {
	 *     Arguments for processing the group block.
	 *
	 *     @type array<int,string> $blocks       Array of blocks to process.
	 *     @type int    $i            Current block index.
	 *     @type int    $block_length Total number of blocks.
	 *     @type string $block        Current block content.
	 *     @type bool   $is_block     Whether current content is a block.
	 *     @type string $group_name   Name of the group block (e.g. 'repeater').
	 * }
	 * @return array{
	 *     blocks: array<int,string>,
	 *     block_length: int,
	 *     group_template: string
	 * } Processed blocks data and group template.
	 */
	private function process_group_block( array $args ): array {
		$blocks       = is_array( $args['blocks'] ) ? $args['blocks'] : [];
		$i            = isset( $args['i'] ) && is_int( $args['i'] ) ? (int) $args['i'] : 0;
		$block_length = isset( $args['block_length'] ) && is_int( $args['block_length'] ) ? (int) $args['block_length'] : 0;
		$block        = isset( $args['block'] ) && is_string( $args['block'] ) ? $args['block'] : '';
		$is_block     = isset( $args['is_block'] ) ? (bool) $args['is_block'] : false;
		$group_name   = isset( $args['group_name'] ) && is_string( $args['group_name'] ) ? $args['group_name'] : '';

		$group_content = $block;

		for ( $j = $i + 1; $j < $block_length; $j++ ) {
			$next_block = $blocks[ $j ] ?? '';
			if ( empty( $next_block ) ) {
				continue;
			}

			$next_parsed_blocks    = parse_blocks( $next_block );
			$next_block_inner_html = isset( $next_parsed_blocks[0]['innerHTML'] ) ? (string) $next_parsed_blocks[0]['innerHTML'] : '';

			$group_content .= $next_block;
			unset( $blocks[ $j ] );

			if ( false !== strpos( $next_block_inner_html, '/wp:srfm/' . $group_name ) ) {
				break;
			}
		}

		$blocks         = array_values( $blocks );
		$block_length   = count( $blocks );
		$group_template = $this->render_single_conversational_block( $i, $block_length, $group_content, $is_block );

		return [
			'blocks'         => $blocks,
			'block_length'   => $block_length,
			'group_template' => $group_template,
		];
	}

	/**
	 * Enqueue scripts.
	 *
	 * @param array<array<string, mixed>> $scripts Array of scripts to enqueue.
	 *
	 * @return void
	 * @since 1.4.0
	 */
	private function enqueue_scripts( $scripts ) {
		foreach ( $scripts as $script ) {
			$script_dep_path = SRFM_PRO_DIR . 'dist/package/pro/' . $script['unique_file'] . '.asset.php';
			$script_dep_data = file_exists( $script_dep_path )
				? include $script_dep_path
				: [
					'dependencies' => [],
					'version'      => SRFM_PRO_VER,
				];

			// Ensure dependencies are arrays.
			$script_dep = array_merge(
				is_array( $script_dep_data['dependencies'] ) ? $script_dep_data['dependencies'] : [],
				is_array( $script['extra_dependencies'] ) ? $script['extra_dependencies'] : []
			);

			// Enqueue script.
			wp_enqueue_script(
				SRFM_PRO_SLUG . '-' . $script['unique_handle'], // Handle.
				SRFM_PRO_URL . 'dist/package/pro/' . $script['unique_file'] . '.js',
				$script_dep, // Dependencies.
				$script_dep_data['version'], // Version.
				true // Enqueue the script in the footer.
			);

			// Register script translations.
			Pro_Helper::register_script_translations( SRFM_PRO_SLUG . '-' . $script['unique_handle'] );
		}
	}
}
