<?php

namespace WPForms\Integrations\Gutenberg;

use WPForms\Frontend\CSSVars;
use WPForms\Integrations\IntegrationInterface;
use WPForms\Admin\Education\StringsTrait;
use WP_Error; // phpcs:ignore WPForms.PHP.UseStatement.UnusedUseStatement
use WP_REST_Response; // phpcs:ignore WPForms.PHP.UseStatement.UnusedUseStatement

/**
 * Form Selector Gutenberg block with live preview.
 *
 * @since 1.4.8
 */
abstract class FormSelector implements IntegrationInterface {

	use StringsTrait;

	/**
	 * Default attributes.
	 *
	 * @since 1.8.1
	 *
	 * @var array
	 */
	const DEFAULT_ATTRIBUTES = [
		'formId'                => '',
		'displayTitle'          => false,
		'displayDesc'           => false,
		'theme'                 => 'default',
		'themeName'             => '',
		'fieldSize'             => 'medium',
		'backgroundImage'       => CSSVars::ROOT_VARS['background-image'],
		'backgroundPosition'    => CSSVars::ROOT_VARS['background-position'],
		'backgroundRepeat'      => CSSVars::ROOT_VARS['background-repeat'],
		'backgroundSizeMode'    => CSSVars::ROOT_VARS['background-size'],
		'backgroundSize'        => CSSVars::ROOT_VARS['background-size'],
		'backgroundWidth'       => CSSVars::ROOT_VARS['background-width'],
		'backgroundHeight'      => CSSVars::ROOT_VARS['background-height'],
		'backgroundUrl'         => CSSVars::ROOT_VARS['background-url'],
		'backgroundColor'       => CSSVars::ROOT_VARS['background-color'],
		'fieldBorderRadius'     => CSSVars::ROOT_VARS['field-border-radius'],
		'fieldBorderStyle'      => CSSVars::ROOT_VARS['field-border-style'],
		'fieldBorderSize'       => CSSVars::ROOT_VARS['field-border-size'],
		'fieldBackgroundColor'  => CSSVars::ROOT_VARS['field-background-color'],
		'fieldBorderColor'      => CSSVars::ROOT_VARS['field-border-color'],
		'fieldTextColor'        => CSSVars::ROOT_VARS['field-text-color'],
		'fieldMenuColor'        => CSSVars::ROOT_VARS['field-menu-color'],
		'labelSize'             => 'medium',
		'labelColor'            => CSSVars::ROOT_VARS['label-color'],
		'labelSublabelColor'    => CSSVars::ROOT_VARS['label-sublabel-color'],
		'labelErrorColor'       => CSSVars::ROOT_VARS['label-error-color'],
		'buttonSize'            => 'medium',
		'buttonBorderStyle'     => CSSVars::ROOT_VARS['button-border-style'],
		'buttonBorderSize'      => CSSVars::ROOT_VARS['button-border-size'],
		'buttonBorderRadius'    => CSSVars::ROOT_VARS['button-border-radius'],
		'buttonBackgroundColor' => CSSVars::ROOT_VARS['button-background-color'],
		'buttonTextColor'       => CSSVars::ROOT_VARS['button-text-color'],
		'buttonBorderColor'     => CSSVars::ROOT_VARS['button-border-color'],
		'pageBreakColor'        => CSSVars::ROOT_VARS['page-break-color'],
		'containerPadding'      => CSSVars::ROOT_VARS['container-padding'],
		'containerBorderStyle'  => CSSVars::ROOT_VARS['container-border-style'],
		'containerBorderWidth'  => CSSVars::ROOT_VARS['container-border-width'],
		'containerBorderColor'  => CSSVars::ROOT_VARS['container-border-color'],
		'containerBorderRadius' => CSSVars::ROOT_VARS['container-border-radius'],
		'containerShadowSize'   => CSSVars::CONTAINER_SHADOW_SIZE['none']['box-shadow'],
		'customCss'             => '',
		'copyPasteJsonValue'    => '',
	];

	/**
	 * Rest API class instance.
	 *
	 * @since 1.8.8
	 *
	 * @var RestApi
	 */
	protected $rest_api_obj;

	/**
	 * Rest API class instance.
	 *
	 * @since 1.8.8
	 *
	 * @var ThemesData
	 */
	protected $themes_data_obj;

	/**
	 * Render engine.
	 *
	 * @since 1.8.1
	 *
	 * @var string
	 */
	protected $render_engine;

	/**
	 * Disabled CSS setting.
	 *
	 * @since 1.8.1
	 *
	 * @var integer
	 */
	protected $disable_css_setting;

	/**
	 * Instance of CSSVars class.
	 *
	 * @since 1.8.1
	 *
	 * @var CSSVars
	 */
	private $css_vars_obj;

	/**
	 * Callbacks registered for wpforms_frontend_container_class filter.
	 *
	 * @since 1.7.5
	 *
	 * @var array
	 */
	private $callbacks = [];

	/**
	 * Currently displayed form Id.
	 *
	 * @since 1.8.8
	 *
	 * @var string|int
	 */
	private $current_form_id = 0;

	/**
	 * Indicate if current integration is allowed to load.
	 *
	 * @since 1.4.8
	 *
	 * @return bool
	 */
	public function allow_load(): bool {

		return function_exists( 'register_block_type' );
	}

	/**
	 * Load an integration.
	 *
	 * @since 1.4.8
	 */
	public function load() {

		$this->render_engine       = wpforms_get_render_engine();
		$this->disable_css_setting = (int) wpforms_setting( 'disable-css', '1' );
		$this->css_vars_obj        = wpforms()->obj( 'css_vars' );

		wpforms()->register_instance( 'formselector_themes_data', $this->themes_data_obj );

		$this->hooks();
	}

	/**
	 * Integration hooks.
	 *
	 * @since 1.4.8
	 */
	protected function hooks() {

		add_action( 'init', [ $this, 'register_block' ] );
		add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_block_editor_assets' ] );
		add_action( 'wpforms_frontend_output_container_after', [ $this, 'replace_wpforms_frontend_container_class_filter' ] );
		add_filter( 'wpforms_frontend_form_action', [ $this, 'form_action_filter' ], 10, 2 );
		add_filter( 'wpforms_forms_anti_spam_v3_is_honeypot_enabled', [ $this, 'filter_is_honeypot_enabled' ] );
		add_filter( 'wpforms_field_richtext_display_editor_is_media_enabled', [ $this, 'disable_richtext_media' ], 10, 2 );
	}

	/**
	 * Disable honeypot in Gutenberg/Block editor.
	 *
	 * @since 1.9.0
	 *
	 * @param bool|mixed $is_enabled True if the honeypot is enabled, false otherwise.
	 *
	 * @return bool Whether to disable the honeypot.
	 */
	public function filter_is_honeypot_enabled( $is_enabled ): bool {

		if ( wpforms_is_rest() ) {
			return false;
		}

		return (bool) $is_enabled;
	}

	/**
	 * Replace the filter registered for wpforms_frontend_container_class.
	 *
	 * @since 1.7.5
	 *
	 * @param array $form_data Form data.
	 *
	 * @return void
	 */
	public function replace_wpforms_frontend_container_class_filter( $form_data ) { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

		if ( empty( $this->callbacks[ $form_data['id'] ] ) ) {
			return;
		}

		$callback = array_shift( $this->callbacks[ $form_data['id'] ] );

		remove_filter( 'wpforms_frontend_container_class', $callback );

		if ( ! empty( $this->callbacks[ $form_data['id'] ] ) ) {
			add_filter( 'wpforms_frontend_container_class', reset( $this->callbacks[ $form_data['id'] ] ), 10, 2 );
		}
	}

	/**
	 * Register WPForms Gutenberg block on the backend.
	 *
	 * @since 1.4.8
	 */
	public function register_block() {

		$attributes = [
			'clientId'              => [
				'type' => 'string',
			],
			'formId'                => [
				'type' => 'string',
			],
			'displayTitle'          => [
				'type' => 'boolean',
			],
			'displayDesc'           => [
				'type' => 'boolean',
			],
			'className'             => [
				'type' => 'string',
			],
			'theme'                 => [
				'type' => 'string',
			],
			'themeName'             => [
				'type' => 'string',
			],
			'fieldSize'             => [
				'type' => 'string',
			],
			'fieldBorderRadius'     => [
				'type' => 'string',
			],
			'fieldBorderStyle'      => [
				'type' => 'string',
			],
			'fieldBorderSize'       => [
				'type' => 'string',
			],
			'fieldBackgroundColor'  => [
				'type' => 'string',
			],
			'fieldBorderColor'      => [
				'type' => 'string',
			],
			'fieldTextColor'        => [
				'type' => 'string',
			],
			'fieldMenuColor'        => [
				'type' => 'string',
			],
			'labelSize'             => [
				'type' => 'string',
			],
			'labelColor'            => [
				'type' => 'string',
			],
			'labelSublabelColor'    => [
				'type' => 'string',
			],
			'labelErrorColor'       => [
				'type' => 'string',
			],
			'buttonSize'            => [
				'type' => 'string',
			],
			'buttonBorderStyle'     => [
				'type' => 'string',
			],
			'buttonBorderSize'      => [
				'type' => 'string',
			],
			'buttonBorderRadius'    => [
				'type' => 'string',
			],
			'buttonBackgroundColor' => [
				'type' => 'string',
			],
			'buttonBorderColor'     => [
				'type' => 'string',
			],
			'buttonTextColor'       => [
				'type' => 'string',
			],
			'pageBreakColor'        => [
				'type' => 'string',
			],
			'backgroundImage'       => [
				'type' => 'string',
			],
			'backgroundPosition'    => [
				'type' => 'string',
			],
			'backgroundRepeat'      => [
				'type' => 'string',
			],
			'backgroundSizeMode'    => [
				'type' => 'string',
			],
			'backgroundSize'        => [
				'type' => 'string',
			],
			'backgroundWidth'       => [
				'type' => 'string',
			],
			'backgroundHeight'      => [
				'type' => 'string',
			],
			'backgroundUrl'         => [
				'type' => 'string',
			],
			'backgroundColor'       => [
				'type' => 'string',
			],
			'containerPadding'      => [
				'type' => 'string',
			],
			'containerBorderStyle'  => [
				'type' => 'string',
			],
			'containerBorderWidth'  => [
				'type' => 'string',
			],
			'containerBorderColor'  => [
				'type' => 'string',
			],
			'containerBorderRadius' => [
				'type' => 'string',
			],
			'containerShadowSize'   => [
				'type' => 'string',
			],
			'customCss'             => [
				'type' => 'string',
			],
			'copyPasteJsonValue'    => [
				'type' => 'string',
			],
		];

		$this->register_styles();

		register_block_type(
			'wpforms/form-selector',
			[
				/**
				 * Modify WPForms block attributes.
				 *
				 * @since 1.5.8.2
				 *
				 * @param array $attributes Attributes.
				 */
				'attributes'      => apply_filters( 'wpforms_gutenberg_form_selector_attributes', $attributes ), // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
				'style'           => 'wpforms-gutenberg-form-selector',
				'editor_style'    => 'wpforms-integrations',
				'render_callback' => [ $this, 'get_form_html' ],
			]
		);
	}

	/**
	 * Register WPForms Gutenberg block styles.
	 *
	 * @since 1.7.4.2
	 */
	protected function register_styles() {

		if ( ! is_admin() ) {
			return;
		}

		$min = wpforms_get_min_suffix();

		wp_register_style(
			'wpforms-integrations',
			WPFORMS_PLUGIN_URL . "assets/css/admin-integrations{$min}.css",
			[ 'dashicons' ],
			WPFORMS_VERSION
		);

		if ( $this->disable_css_setting === 3 ) {
			return;
		}

		$css_file = $this->disable_css_setting === 2 ? 'base' : 'full';

		wp_register_style(
			'wpforms-gutenberg-form-selector',
			WPFORMS_PLUGIN_URL . "assets/css/frontend/{$this->render_engine}/wpforms-{$css_file}{$min}.css",
			[ 'wp-edit-blocks', 'wpforms-integrations' ],
			WPFORMS_VERSION
		);
	}

	/**
	 * Load WPForms Gutenberg block scripts.
	 *
	 * @since 1.4.8
	 */
	public function enqueue_block_editor_assets() {

		$min = wpforms_get_min_suffix();

		wp_enqueue_style( 'wpforms-integrations' );

		wp_set_script_translations( 'wpforms-gutenberg-form-selector', 'wpforms-lite' );

		// jQuery.Confirm Reloaded.
		wp_enqueue_style(
			'jquery-confirm',
			WPFORMS_PLUGIN_URL . 'assets/lib/jquery.confirm/jquery-confirm.min.css',
			null,
			'1.0.0'
		);

		wp_enqueue_script(
			'jquery-confirm',
			WPFORMS_PLUGIN_URL . 'assets/lib/jquery.confirm/jquery-confirm.min.js',
			[ 'jquery' ],
			'1.0.0',
			false
		);

		// Support for the legacy form selector.
		// It is located in the common namespace.
		if ( $this->is_legacy_block() ) {
			wp_enqueue_script(
				'wpforms-gutenberg-form-selector',
				WPFORMS_PLUGIN_URL . "assets/js/integrations/gutenberg/formselector-legacy.es5{$min}.js",
				[ 'wp-blocks', 'wp-i18n', 'wp-element', 'jquery' ],
				WPFORMS_VERSION,
				true
			);

			return;
		}

		if ( $this->render_engine === 'modern' ) {
			wp_enqueue_script(
				'wpforms-modern',
				WPFORMS_PLUGIN_URL . "assets/js/frontend/wpforms-modern{$min}.js",
				[ 'wpforms-gutenberg-form-selector' ],
				WPFORMS_VERSION,
				true
			);
		}

		wp_enqueue_script(
			'wpforms-admin-education-core',
			WPFORMS_PLUGIN_URL . "assets/js/admin/education/core{$min}.js",
			[ 'jquery', 'jquery-confirm' ],
			WPFORMS_VERSION,
			true
		);

		wp_localize_script(
			'wpforms-admin-education-core',
			'wpforms_education',
			$this->get_js_strings()
		);
	}

	/**
	 * Whether the block is legacy.
	 *
	 * @since 1.8.8
	 */
	protected function is_legacy_block() {

		return version_compare( $GLOBALS['wp_version'], '6.0', '<' );
	}

	/**
	 * Register API route for Gutenberg block.
	 *
	 * @since 1.8.4
	 * @deprecated 1.8.8
	 */
	public function register_api_route() {

		_deprecated_function( __METHOD__, '1.8.8 of the WPForms plugin', '\WPForms\Integrations\Gutenberg\RestApi::register_api_routes()' );

		$this->rest_api_obj->register_api_routes();
	}

	/**
	 * Wrap localized data in a protected WP_REST_Response object.
	 *
	 * @since 1.8.4
	 * @deprecated 1.8.8
	 *
	 * @see https://developer.wordpress.org/reference/functions/rest_ensure_response/
	 *
	 * @return WP_Error|WP_REST_Response
	 */
	public function protected_data_callback() {

		_deprecated_function( __METHOD__, '1.8.8 of the WPForms plugin', '\WPForms\Integrations\Gutenberg\RestApi::get_forms()' );

		return $this->rest_api_obj->get_forms();
	}

	/**
	 * Check if a user has permission to access private data.
	 *
	 * @since 1.8.4
	 * @deprecated 1.8.8
	 *
	 * @see https://developer.wordpress.org/rest-api/extending-the-rest-api/routes-and-endpoints/#permissions-callback
	 *
	 * @return true|WP_Error True if a user has permission.
	 */
	public function protected_permissions_callback() {

		_deprecated_function( __METHOD__, '1.8.8 of the WPForms plugin', '\WPForms\Integrations\Gutenberg\RestApi::permissions_check()' );

		return $this->rest_api_obj->permissions_check();
	}

	/**
	 * Get localize data.
	 *
	 * @since 1.8.1
	 *
	 * @return array
	 */
	public function get_localize_data(): array {

		$strings = [
			'title'                        => esc_html__( 'WPForms', 'wpforms-lite' ),
			'description'                  => esc_html__( 'Select and display one of your forms.', 'wpforms-lite' ),
			'form_keywords'                => [
				esc_html__( 'form', 'wpforms-lite' ),
				esc_html__( 'contact', 'wpforms-lite' ),
				esc_html__( 'survey', 'wpforms-lite' ),
			],
			'form_select'                  => esc_html__( 'Select a Form', 'wpforms-lite' ),
			'form_settings'                => esc_html__( 'Form Settings', 'wpforms-lite' ),
			'form_edit'                    => esc_html__( 'Edit Form', 'wpforms-lite' ),
			'form_entries'                 => esc_html__( 'View Entries', 'wpforms-lite' ),
			'themes'                       => esc_html__( 'Themes', 'wpforms-lite' ),
			'theme_name'                   => esc_html__( 'Theme Name', 'wpforms-lite' ),
			'theme_delete'                 => esc_html__( 'Delete Theme', 'wpforms-lite' ),
			'theme_delete_title'           => esc_html__( 'Delete Form Theme', 'wpforms-lite' ),
			// Translators: %1$s: Theme name.
			'theme_delete_confirm'         => esc_html__( 'Are you sure you want to delete the %1$s theme?', 'wpforms-lite' ),
			'theme_delete_cant_undone'     => esc_html__( 'This cannot be undone.', 'wpforms-lite' ),
			'theme_delete_yes'             => esc_html__( 'Yes, Delete', 'wpforms-lite' ),
			'theme_copy'                   => esc_html__( 'Copy', 'wpforms-lite' ),
			'theme_custom'                 => esc_html__( 'Custom Theme', 'wpforms-lite' ),
			'theme_noname'                 => esc_html__( 'Noname Theme', 'wpforms-lite' ),
			'field_styles'                 => esc_html__( 'Field Styles', 'wpforms-lite' ),
			'field_label'                  => esc_html__( 'Field Label', 'wpforms-lite' ),
			'field_sublabel'               => esc_html__( 'Field Sublabel', 'wpforms-lite' ),
			'field_border'                 => esc_html__( 'Field Border', 'wpforms-lite' ),
			'label_styles'                 => esc_html__( 'Label Styles', 'wpforms-lite' ),
			'button_background'            => esc_html__( 'Button Background', 'wpforms-lite' ),
			'button_text'                  => esc_html__( 'Button Text', 'wpforms-lite' ),
			'button_styles'                => esc_html__( 'Button Styles', 'wpforms-lite' ),
			'container_styles'             => esc_html__( 'Container Styles', 'wpforms-lite' ),
			'background_styles'            => esc_html__( 'Background Styles', 'wpforms-lite' ),
			'remove_image'                 => esc_html__( 'Remove Image', 'wpforms-lite' ),
			'position'                     => esc_html__( 'Position', 'wpforms-lite' ),
			'top_left'                     => esc_html__( 'Top Left', 'wpforms-lite' ),
			'top_center'                   => esc_html__( 'Top Center', 'wpforms-lite' ),
			'top_right'                    => esc_html__( 'Top Right', 'wpforms-lite' ),
			'center_left'                  => esc_html__( 'Center Left', 'wpforms-lite' ),
			'center_center'                => esc_html__( 'Center Center', 'wpforms-lite' ),
			'center_right'                 => esc_html__( 'Center Right', 'wpforms-lite' ),
			'bottom_left'                  => esc_html__( 'Bottom Left', 'wpforms-lite' ),
			'bottom_center'                => esc_html__( 'Bottom Center', 'wpforms-lite' ),
			'bottom_right'                 => esc_html__( 'Bottom Right', 'wpforms-lite' ),
			'repeat'                       => esc_html__( 'Repeat', 'wpforms-lite' ),
			'no_repeat'                    => esc_html__( 'No Repeat', 'wpforms-lite' ),
			'repeat_x'                     => esc_html__( 'Repeat Horizontal', 'wpforms-lite' ),
			'repeat_y'                     => esc_html__( 'Repeat Vertical', 'wpforms-lite' ),
			'tile'                         => esc_html__( 'Tile', 'wpforms-lite' ),
			'cover'                        => esc_html__( 'Cover', 'wpforms-lite' ),
			'dimensions'                   => esc_html__( 'Dimensions', 'wpforms-lite' ),
			'width'                        => esc_html__( 'Width', 'wpforms-lite' ),
			'height'                       => esc_html__( 'Height', 'wpforms-lite' ),
			'button_color_notice'          => esc_html__( 'Also used for other fields like Multiple Choice, Checkboxes, Rating, and NPS Survey.', 'wpforms-lite' ),
			'advanced'                     => esc_html__( 'Advanced', 'wpforms-lite' ),
			'additional_css_classes'       => esc_html__( 'Additional CSS Classes', 'wpforms-lite' ),
			'form_selected'                => esc_html__( 'Form', 'wpforms-lite' ),
			'show_title'                   => esc_html__( 'Show Title', 'wpforms-lite' ),
			'show_description'             => esc_html__( 'Show Description', 'wpforms-lite' ),
			'panel_notice_head'            => esc_html__( 'Heads up!', 'wpforms-lite' ),
			'panel_notice_text'            => esc_html__( 'Do not forget to test your form.', 'wpforms-lite' ),
			'panel_notice_link'            => esc_url( wpforms_utm_link( 'https://wpforms.com/docs/how-to-properly-test-your-wordpress-forms-before-launching-checklist/', 'gutenberg' ) ),
			'panel_notice_link_text'       => esc_html__( 'Check out our complete guide!', 'wpforms-lite' ),
			'update_wp_notice_head'        => esc_html__( 'Want to customize your form styles without editing CSS?', 'wpforms-lite' ),
			'update_wp_notice_text'        => esc_html__( 'Update WordPress to the latest version to use our modern markup and unlock the controls below.', 'wpforms-lite' ),
			'update_wp_notice_link'        => esc_url( wpforms_utm_link( 'https://wpforms.com/docs/styling-your-forms/', 'Block Settings', 'Form Styles Documentation' ) ),
			'learn_more'                   => esc_html__( 'Learn more', 'wpforms-lite' ),
			'use_modern_notice_head'       => esc_html__( 'Want to customize your form styles without editing CSS?', 'wpforms-lite' ),
			'use_modern_notice_text'       => esc_html__( 'Enable modern markup in your WPForms settings to unlock the controls below.', 'wpforms-lite' ),
			'use_modern_notice_link'       => esc_url( wpforms_utm_link( 'https://wpforms.com/docs/styling-your-forms/', 'Block Settings', 'Form Styles Documentation' ) ),
			'lead_forms_panel_notice_head' => esc_html__( 'Form Styles are disabled because Lead Form Mode is turned on.', 'wpforms-lite' ),
			'lead_forms_panel_notice_text' => esc_html__( 'To change the styling for this form, open it in the form builder and edit the options in the Lead Forms settings.', 'wpforms-lite' ),
			'size'                         => esc_html__( 'Size', 'wpforms-lite' ),
			'padding'                      => esc_html__( 'Padding', 'wpforms-lite' ),
			'background'                   => esc_html__( 'Background', 'wpforms-lite' ),
			'border'                       => esc_html__( 'Border', 'wpforms-lite' ),
			'text'                         => esc_html__( 'Text', 'wpforms-lite' ),
			'menu'                         => esc_html__( 'Menu', 'wpforms-lite' ),
			'image'                        => esc_html__( 'Image', 'wpforms-lite' ),
			'media_library'                => esc_html__( 'Media Library', 'wpforms-lite' ),
			'choose_image'                 => esc_html__( 'Choose Image', 'wpforms-lite' ),
			'stock_photo'                  => esc_html__( 'Stock Photo', 'wpforms-lite' ),
			'border_radius'                => esc_html__( 'Border Radius', 'wpforms-lite' ),
			'border_size'                  => esc_html__( 'Border Size', 'wpforms-lite' ),
			'border_style'                 => esc_html__( 'Border Style', 'wpforms-lite' ),
			'none'                         => esc_html__( 'None', 'wpforms-lite' ),
			'solid'                        => esc_html__( 'Solid', 'wpforms-lite' ),
			'dashed'                       => esc_html__( 'Dashed', 'wpforms-lite' ),
			'dotted'                       => esc_html__( 'Dotted', 'wpforms-lite' ),
			'double'                       => esc_html__( 'Double', 'wpforms-lite' ),
			'shadow_size'                  => esc_html__( 'Shadow', 'wpforms-lite' ),
			'border_width'                 => esc_html__( 'Border Size', 'wpforms-lite' ),
			'border_color'                 => esc_html__( 'Border', 'wpforms-lite' ),
			'colors'                       => esc_html__( 'Colors', 'wpforms-lite' ),
			'label'                        => esc_html__( 'Label', 'wpforms-lite' ),
			'sublabel_hints'               => esc_html__( 'Sublabel & Hint', 'wpforms-lite' ),
			'error_message'                => esc_html__( 'Error Message', 'wpforms-lite' ),
			'small'                        => esc_html__( 'Small', 'wpforms-lite' ),
			'medium'                       => esc_html__( 'Medium', 'wpforms-lite' ),
			'large'                        => esc_html__( 'Large', 'wpforms-lite' ),
			'btn_yes'                      => esc_html__( 'Yes', 'wpforms-lite' ),
			'btn_no'                       => esc_html__( 'No', 'wpforms-lite' ),
			'copy_paste_settings'          => esc_html__( 'Copy / Paste Style Settings', 'wpforms-lite' ),
			'copy_paste_error'             => esc_html__( 'There was an error parsing your JSON code. Please check your code and try again.', 'wpforms-lite' ),
			'copy_paste_notice'            => esc_html__( 'If you\'ve copied style settings from another form, you can paste them here to add the same styling to this form. Any current style settings will be overwritten.', 'wpforms-lite' ),
			'custom_css'                   => esc_html__( 'Custom CSS', 'wpforms-lite' ),
			'custom_css_notice'            => esc_html__( 'Further customize the look of this form without having to edit theme files.', 'wpforms-lite' ),
			// Translators: %1$s: Opening strong tag, %2$s: Closing strong tag.
			'wpforms_empty_info'           => sprintf( esc_html__( 'You can use %1$sWPForms%2$s to build contact forms, surveys, payment forms, and more with just a few clicks.', 'wpforms-lite' ), '<strong>','</strong>' ),
			// Translators: %1$s: Opening anchor tag, %2$s: Closing achor tag.
			'wpforms_empty_help'           => sprintf( esc_html__( 'Need some help? Check out our %1$scomprehensive guide.%2$s', 'wpforms-lite' ), '<a target="_blank" href="' . esc_url( wpforms_utm_link( 'https://wpforms.com/docs/creating-first-form/', 'gutenberg', 'Create Your First Form Documentation' ) ) . '">','</a>' ),
			'other_styles'                 => esc_html__( 'Other Styles', 'wpforms-lite' ),
			'page_break'                   => esc_html__( 'Page Break', 'wpforms-lite' ),
			'rating'                       => esc_html__( 'Rating', 'wpforms-lite' ),
			'heads_up'                     => esc_html__( 'Heads Up!', 'wpforms-lite' ),
			'form_not_available_message'   => esc_html__( 'It looks like the form you had selected is in the Trash or has been permanently deleted.', 'wpforms-lite' ),
		];

		return [
			'logo_url'          => WPFORMS_PLUGIN_URL . 'assets/images/wpforms-logo.svg',
			'block_preview_url' => WPFORMS_PLUGIN_URL . 'assets/images/integrations/gutenberg/block-preview.png',
			'block_empty_url'   => WPFORMS_PLUGIN_URL . 'assets/images/empty-states/no-forms.svg',
			'route_namespace'   => RestApi::ROUTE_NAMESPACE,
			'wpnonce'           => wp_create_nonce( 'wpforms-gutenberg-form-selector' ),
			'urls'              => [
				'form_url'    => admin_url( 'admin.php?page=wpforms-builder&view=fields&form_id={ID}' ),
				'entries_url' => admin_url( 'admin.php?view=list&page=wpforms-entries&form_id={ID}' ),
			],
			'forms'             => $this->get_form_list(),
			'strings'           => $strings,
			'isAdmin'           => current_user_can( 'manage_options' ),
			'isPro'             => wpforms()->is_pro(),
			'defaults'          => self::DEFAULT_ATTRIBUTES,
			'is_modern_markup'  => $this->render_engine === 'modern',
			'is_full_styling'   => $this->disable_css_setting === 1,
			'wpforms_guide'     => esc_url( wpforms_utm_link( 'https://wpforms.com/docs/creating-first-form/', 'gutenberg', 'Create Your First Form Documentation' ) ),
			'get_started_url'   => esc_url( admin_url( 'admin.php?page=wpforms-builder' ) ),
			'sizes'             => [
				'field-size'            => CSSVars::FIELD_SIZE,
				'label-size'            => CSSVars::LABEL_SIZE,
				'button-size'           => CSSVars::BUTTON_SIZE,
				'container-shadow-size' => CSSVars::CONTAINER_SHADOW_SIZE,
			],
		];
	}

	/**
	 * Get the form list.
	 *
	 * @since 1.8.8
	 *
	 * @return array
	 * @noinspection NullPointerExceptionInspection
	 */
	public function get_form_list(): array {

		$forms = wpforms()->obj( 'form' )->get( '', [ 'order' => 'DESC' ] );

		if ( empty( $forms ) ) {
			return [];
		}

		return array_map(
			static function ( $form ) {
				$form->post_title = htmlspecialchars_decode( $form->post_title, ENT_QUOTES );
				$max_length       = 47;
				$form->post_title = trim( mb_substr( trim( $form->post_title ), 0, $max_length ) );
				$form->post_title = mb_strlen( $form->post_title ) === $max_length ? $form->post_title . '…' : $form->post_title;

				return $form;
			},
			$forms
		);
	}

	/**
	 * Let's WP know that we have translation strings on our block script.
	 *
	 * @since 1.8.3
	 * @deprecated 1.8.5
	 */
	public function enable_block_translations() {

		_deprecated_function( __METHOD__, '1.8.5' );
	}

	/**
	 * Filter form action.
	 *
	 * @since 1.8.8
	 *
	 * @param string|mixed $action    Form action.
	 * @param array|mixed  $form_data Form data.
	 *
	 * @return string
	 */
	public function form_action_filter( $action, $form_data ): string {

		if ( $this->is_gb_editor() ) {

			// Remove inappropriate form action URL that contains all the block attributes.
			$action = '';
		}

		return (string) $action;
	}

	/**
	 * Get form HTML to display in a WPForms Gutenberg block.
	 *
	 * @since 1.4.8
	 *
	 * @param array|mixed $attr Attributes passed by WPForms Gutenberg block.
	 *
	 * @return string
	 */
	public function get_form_html( $attr ): string {

		$attr = (array) $attr;

		$id = ! empty( $attr['formId'] ) ? absint( $attr['formId'] ) : 0;

		$this->current_form_id = $id;

		if ( empty( $id ) ) {
			return '';
		}

		if ( $this->is_gb_editor() ) {
			$this->disable_fields_in_gb_editor();
		}

		$title = ! empty( $attr['displayTitle'] );
		$desc  = ! empty( $attr['displayDesc'] );

		$this->add_class_callback( $id, $attr );

		// Maybe override block attributes with the theme settings.
		$attr = $this->maybe_override_block_attributes( $attr );

		// Get block content.
		$content = $this->get_content( $id, $title, $desc, $attr );

		// phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName

		/**
		 * Filter Gutenberg block content.
		 *
		 * @since 1.5.8.2
		 *
		 * @param string $content Block content.
		 * @param int    $id      Form id.
		 */
		return (string) apply_filters( 'wpforms_gutenberg_block_form_content', $content, $id );

		// phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName
	}

	/**
	 * Maybe override block attributes.
	 *
	 * This method is used to override block attributes with the theme settings.
	 *
	 * @since 1.8.8
	 *
	 * @param array $attr Attributes passed by WPForms Gutenberg block.
	 *
	 * @return array
	 */
	private function maybe_override_block_attributes( array $attr ): array {

		$theme_slug = (string) ( $attr['theme'] ?? '' );

		// Previously added blocks (FS 1.0) don't have the themeName attribute.
		// To preserve existing styling of such old blocks, we shouldn't override attributes.
		if ( ! isset( $attr['themeName'] ) || ( empty( $attr['themeName'] ) && $theme_slug === 'default' ) ) {
			return $attr;
		}

		$theme_data = $this->themes_data_obj->get_theme( $theme_slug );

		// Theme doesn't exist, let's return.
		if ( ! $theme_data ) {
			return $attr;
		}

		// Override block attributes with the theme settings.
		return array_merge( $attr, $theme_data['settings'] );
	}

	/**
	 * Add class callback.
	 *
	 * @since 1.8.1
	 *
	 * @param int   $id   Form id.
	 * @param array $attr Form attributes.
	 *
	 * @return void
	 */
	private function add_class_callback( $id, $attr ) { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

		$class_callback = static function ( $classes, $form_data ) use ( $id, $attr ) {

			if ( (int) $form_data['id'] !== $id ) {
				return $classes;
			}

			$cls = [];

			// Add custom class to form container.
			if ( ! empty( $attr['className'] ) ) {
				$cls = array_map( 'esc_attr', explode( ' ', $attr['className'] ) );
			}

			// Add classes to identify that the form displays inside the block.
			$cls[] = 'wpforms-block';

			if ( ! empty( $attr['clientId'] ) ) {
				$cls[] = 'wpforms-block-' . $attr['clientId'];
			}

			return array_unique( array_merge( $classes, $cls ) );
		};

		if ( empty( $this->callbacks[ $id ] ) ) {
			add_filter( 'wpforms_frontend_container_class', $class_callback, 10, 2 );
		}

		$this->callbacks[ $id ][] = $class_callback;
	}

	/**
	 * Get content.
	 *
	 * @since 1.8.1
	 *
	 * @param int   $id    Form id.
	 * @param bool  $title Form title is not empty.
	 * @param bool  $desc  Form desc is not empty.
	 * @param array $attr  Form attributes.
	 *
	 * @return string
	 */
	private function get_content( $id, $title, $desc, $attr ): string {

		/**
		 * Filter allow render block content flag.
		 *
		 * @since 1.8.8
		 *
		 * @param bool $allow_render Allow render flag. Defaults to `true`.
		 */
		$allow_render = (bool) apply_filters( 'wpforms_integrations_gutenberg_form_selector_allow_render', true );

		if ( ! $allow_render ) {
			return '';
		}

		ob_start();

		// phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName

		/**
		 * Fires before Gutenberg block output.
		 *
		 * @since 1.5.8.2
		 */
		do_action( 'wpforms_gutenberg_block_before' );

		/**
		 * Filter block title display flag.
		 *
		 * @since 1.5.8.2
		 *
		 * @param bool $title Title display flag.
		 * @param int  $id    Form id.
		 */
		$title = (bool) apply_filters( 'wpforms_gutenberg_block_form_title', $title, $id );

		/**
		 * Filter block description display flag.
		 *
		 * @since 1.5.8.2
		 *
		 * @param bool $desc Description display flag.
		 * @param int  $id   Form id.
		 */
		$desc = (bool) apply_filters( 'wpforms_gutenberg_block_form_desc', $desc, $id );

		$this->output_css_vars( $attr );
		$this->output_custom_css( $attr );

		wpforms_display( $id, $title, $desc );

		/**
		 * Fires after Gutenberg block output.
		 *
		 * @since 1.5.8.2
		 */
		do_action( 'wpforms_gutenberg_block_after' );

		// phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName

		$content = (string) ob_get_clean();

		if ( ! $this->is_gb_editor() ) {
			return $content;
		}

		if ( empty( $content ) ) {
			return '<div class="components-placeholder"><div class="components-placeholder__label"></div>' .
						'<div class="components-placeholder__fieldset">' .
						esc_html__( 'The form cannot be displayed.', 'wpforms-lite' ) .
						'</div></div>';
		}

		/**
		 * Unfortunately, the inline 'script' tag cannot be executed in the GB editor.
		 * This is the hacky way to trigger custom event on form loaded in the Block Editor / GB / FSE.
		 */

		// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_var_export
		$content .= sprintf(
			'<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" onLoad="
				window.top.dispatchEvent(
					new CustomEvent(
						\'wpformsFormSelectorFormLoaded\',
						{
							detail: {
								formId: %1$s,
								title: %2$s,
								desc: %3$s,
								block: this.closest( \'.wp-block\' )
							}
						}
					)
				);
			" class="wpforms-pix-trigger" alt="">',
			absint( $id ),
			var_export( (bool) $title, true ),
			var_export( (bool) $desc, true )
		);

		// phpcs:enable WordPress.PHP.DevelopmentFunctions.error_log_var_export

		return $content;
	}

	/**
	 * Checking if is Gutenberg REST API call.
	 *
	 * @since 1.5.7
	 *
	 * @return bool True if is Gutenberg REST API call.
	 */
	public function is_gb_editor(): bool {

		// TODO: Find a better way to check if is GB editor API call.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return defined( 'REST_REQUEST' ) && REST_REQUEST && ! empty( $_REQUEST['context'] ) && $_REQUEST['context'] === 'edit';
	}

	/**
	 * Disable form fields if called from the Gutenberg editor.
	 *
	 * @since 1.7.5
	 *
	 * @return void
	 */
	private function disable_fields_in_gb_editor() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

		add_filter(
			'wpforms_frontend_container_class',
			static function ( $classes ) {

				$classes[] = 'wpforms-gutenberg-form-selector';

				return $classes;
			}
		);
		add_action(
			'wpforms_frontend_output',
			static function () {

				echo '<fieldset disabled>';
			},
			3
		);
		add_action(
			'wpforms_frontend_output',
			static function () {

				echo '</fieldset>';
			},
			30
		);
	}

	/**
	 * Output CSS variables for the particular form.
	 *
	 * @since 1.8.1
	 *
	 * @param array $attr Attributes passed by WPForms Gutenberg block.
	 */
	private function output_css_vars( $attr ) {

		if ( empty( $this->css_vars_obj ) || ! method_exists( $this->css_vars_obj, 'get_vars' ) ) {
			return;
		}

		$this->css_vars_obj->output_root();

		if ( $this->render_engine === 'classic' || $this->disable_css_setting !== 1 ) {
			return;
		}

		$css_vars = $this->css_vars_obj->get_customized_css_vars( $attr );

		if ( empty( $css_vars ) ) {
			return;
		}

		$style_id = "#wpforms-css-vars-{$attr['formId']}-block-{$attr['clientId']}";

		/**
		 * Filter the CSS selector for output CSS variables for styling the GB block form.
		 *
		 * @since 1.8.1
		 *
		 * @param string $selector The CSS selector for output CSS variables for styling the GB block form.
		 * @param array  $attr     Attributes passed by WPForms Gutenberg block.
		 * @param array  $css_vars CSS variables data.
		 */
		$vars_selector = apply_filters(
			'wpforms_integrations_gutenberg_form_selector_output_css_vars_selector',
			"#wpforms-{$attr['formId']}.wpforms-block-{$attr['clientId']}",
			$attr,
			$css_vars
		);

		$this->css_vars_obj->output_selector_vars( $vars_selector, $css_vars, $style_id, $this->current_form_id );
	}

	/**
	 * Output custom CSS styles.
	 *
	 * @since 1.8.8
	 *
	 * @param array $attr Attributes passed by WPForms Gutenberg block.
	 */
	private function output_custom_css( $attr ) {

		if ( wpforms_get_render_engine() === 'classic' ) {
			return;
		}

		$custom_css = trim( $attr['customCss'] ?? '' );

		if ( empty( $custom_css ) ) {
			return;
		}

		$style_id = "#wpforms-custom-css-{$attr['formId']}-block-{$attr['clientId']}";

		printf(
			'<style id="%1$s">
				%2$s
			</style>',
			sanitize_key( $style_id ),
 			esc_html( $custom_css )
		);
	}

	/**
	 * Disable loading media for the richtext editor for edit action to prevent script conflicts.
	 *
	 * @since 1.9.1
	 *
	 * @param bool|mixed $media_enabled Whether to enable media.
	 * @param array      $field         Field data.
	 *
	 * @return bool
	 */
	public function disable_richtext_media( $media_enabled, array $field ): bool {

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] === 'edit' && is_admin() ) {
			return false;
		}

		return (bool) $media_enabled;
	}
}
