<?php
declare( strict_types=1 );

namespace FiboFilters\Integrations\Plugins\Elementor;

use Elementor\Plugin;
use Elementor\Widgets_Manager;
use ElementorPro\Modules\Woocommerce\Widgets\Products;
use FiboFilters\Config\AssetsLoader;
use FiboFilters\Config\Env;
use FiboFilters\Filtering\Front;
use FiboFilters\Index\Sources;
use FiboFilters\Integrations\Multilingual;
use FiboFilters\Integrations\Plugins\AbstractPlugin;
use FiboFilters\Integrations\Plugins\Elementor\Utils as ElementorUtils;
use FiboFilters\Settings\Settings;
use FiboFilters\Util\Helpers;
use FiboFilters\WooCommerce\Helper as WooCommerceHelper;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class Elementor
 */
class Elementor extends AbstractPlugin {

	private $loop_grid_templates;

	/** @var ElementorUtils */
	private $elementor_utils;

	public function __construct( ElementorUtils $utils, Front $front, Settings $settings, WooCommerceHelper $wc_helper, Sources $sources, Multilingual $multilingual, AssetsLoader $assets_loader ) {
		parent::__construct( $front, $settings, $wc_helper, $sources, $multilingual, $assets_loader );

		$this->elementor_utils = $utils;
	}

	public function init(): void {
		add_action( 'elementor/widgets/register', [ $this, 'register_widgets' ] );
		add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'editor_enqueue_scripts' ] );
		add_action( 'wp_enqueue_scripts', [ $this, 'front_enqueue_scripts' ], 20 );

		if ( defined( 'ELEMENTOR_PRO_VERSION' ) && class_exists( '\ElementorPro\Plugin' ) ) {
			add_filter( 'woocommerce_product_loop_start', [ $this, 'add_own_class_to_product_loop_start' ], PHP_INT_MAX - 10 );

			// Support for custom pages with "Products" widget.
			add_action( 'elementor/element/woocommerce-products/section_query/before_section_end', [ $this, 'add_fibofilters_switch_to_woocommerce_products_widget' ], 10, 2 );
			add_filter( 'fibofilters/request/context_and_query_vars', [ $this, 'support_page_with_products' ], 10, 2 );

			// Support for loop grid widget with other sources than "Current Query".
			add_action( 'elementor/element/loop-grid/section_query/before_section_end', [ $this, 'add_fibofilters_switch_to_woocommerce_loop_grid' ], 10, 2 );
		}

		// Set alternative pagination selector.
		add_filter( 'fibofilters/config/pagination_selectors', [ $this, 'add_pagination_selectors' ] );

		// Support for the Loop Grid widget https://elementor.com/help/loop-grid/.
		$this->register_settings();
		add_action( 'fibofilters/request/context_and_query_vars', [ $this, 'loop_grid_widget_support' ], 15, 2 );
	}

	/**
	 *  ╭─────────────────────╮
	 *  | Pagination selector |
	 *  ╰─────────────────────╯
	 * Add another pagination selector that could be in use.
	 *
	 * @param array $selectors Selectors.
	 */
	public function add_pagination_selectors( array $selectors ): array {
		$selectors[] = '.elementor-pagination';

		return $selectors;
	}

	/**
	 * Check if Elementor Pro is active
	 *
	 * @return bool
	 */
	public function is_elementor_pro(): bool {
		return defined( 'ELEMENTOR_PRO_VERSION' ) && class_exists( '\ElementorPro\Plugin' );
	}

	/**
	 * Get link to the documentation where the integration is described.
	 *
	 * @return string
	 */
	public function get_documentation_link(): string {
		return esc_url( Env::$doc_url . 'plugin-integrations/elementor/' );
	}

	/**
	 * Add settings related to Elementor to the WooCommerce -> FiboFilters -> Integration tab.
	 *
	 * @return void
	 */
	public function register_settings() {

		// Break early if there is no Pro version of the Elementor plugin.
		if ( ! $this->is_elementor_pro() ) {
			return;
		}

		add_filter( 'fibofilters/settings/integrations_section_enabled', '__return_true' );

		add_filter(
			'fibofilters/settings/section=integrations',
			function ( array $settings ): array {

				/* translators: 1: Documentation URL */
				$head_desc          = sprintf( _x( 'Options for integration with the Elementor plugin. A full description of the integration can be found in <a target="_blank" href="%s">the documentation</a>.', '[admin]', 'fibofilters' ), $this->get_documentation_link() );
				$loop_grid_docs_url = 'https://elementor.com/help/loop-grid/';

				$settings[10] = [
					'name'        => 'elementor_header',
					/* translators: 1: Version of Elementor */
					'label'       => sprintf( _x( 'Elementor Pro (v%s)', '[admin]', 'fibofilters' ), ELEMENTOR_PRO_VERSION ),
					'description' => $head_desc,
					'type'        => 'header',
					'group'       => 'integration_elementor',
				];

				/**
				 * We can check if a current page has a loop grid widget too late to change the FiboFilters config dynamically.
				 * Instead, we check if a user has any templates including the loop grid widget. If yes, this option will be enabled by default.
				 */
				$has_loop_grid = ! empty( $this->get_templates_with_product_loop_grid() );

				$settings[15] = [
					'name'        => 'elementor_loop_grid_widget_support',
					'type'        => 'toggle',
					'label'       => _x( 'Support for Loop Grid widget', '[admin]', 'fibofilters' ),
					/* translators: 1: Documentation URL */
					'description' => sprintf( _x( 'If you use the <a href="%s" target="_blank">loop grid widget</a> to display products in the catalog, this option should be enabled. Instead filters will not be displayed, and product will not be loaded.', '[admin]', 'fibofilters' ), $loop_grid_docs_url ),
					'default'     => $has_loop_grid,
					'schema'      => [
						'type' => 'boolean',
					],
					'group'       => 'integration_elementor',
				];

				return $settings;
			}
		);
	}

	/**
	 * @param Widgets_Manager $widgets_manager Widgets manager.
	 */
	public function register_widgets( $widgets_manager ): void {
		$widgets_manager->register( new FiboFiltersWidget() );
	}

	public function editor_enqueue_scripts(): void {
		wp_enqueue_style(
			'fibofilters-fiboicon',
			Env::$static_url . '/icon-font/fiboicon.css',
			[],
			Env::$version
		);
	}

	public function front_enqueue_scripts(): void {
		if ( ! class_exists( '\Elementor\Plugin' ) ) {
			return;
		}

		// Skip color overrides if active theme integration does this.
		$theme = apply_filters( 'fibofilters/integrations/themes/active_integration', false );
		if ( isset( $theme['args']['integration_scope'] ) && is_array( $theme['args']['integration_scope'] ) && in_array( 'color_replacement', $theme['args']['integration_scope'], true ) ) {
			return;
		}

		wp_add_inline_style(
			'fibofilters',
			'body{
				--fibofilters--colors--base: var( --e-global-color-primary, var( --fibofilters--colors--base-org ) );
			}'
		);

		$link_color = Plugin::$instance->kits_manager->get_current_settings( 'link_normal_color' );
		if ( ! empty( $link_color ) ) {
			wp_add_inline_style(
				'fibofilters',
				"body{
				--fibofilters--colors--link: {$link_color};
			}"
			);
		}
	}

	public function loop_grid_widget_support( array $args, \WP_Query $query ) {
		list ($context, $query_vars ) = $args;

		$support_for_loop_grid = $this->settings->get( 'integrations_elementor_loop_grid_widget_support' );

		// Break early if support for the loop grid widget is disabled.
		if ( ! $support_for_loop_grid ) {
			return $args;
		}

		// Break early if the page is not the main loop and contains a "Products" widget.
		if ( ! empty( $context ) && isset( $context['internal']['is_page_with_elementor_woocommerce_products'] ) ) {
			return $args;
		}

		$element = $this->elementor_utils->get_element_for_integrate_with_it_on_archive( 'loop-grid' );

		if ( empty( $element ) ) {
			return $args;
		}

		$settings = $element->get_active_settings();

		// Break if query source is not "Current Query" and integration with FiboFilters is disabled.
		if (
			$settings['product_query_post_type'] !== 'current_query' &&
			( ! isset( $settings['fibofilters_integration'] ) || $settings['fibofilters_integration'] !== 'yes' )
		) {
			return $args;
		}

		/*
		 * ╭────────────────────────────────────────────────╮
		 * | Loop Grid - config: products fetching strategy |
		 * ╰────────────────────────────────────────────────╯
		 *
		 * Necessarily, because Elementor loop grid widget doesn't use template parts.
		 */
		add_filter(
			'fibofilters/config/products_fetching_strategy',
			function () {
				return 'page';
			},
			15
		);

		add_filter(
			'elementor/frontend/widget/before_render',
			function ( $element ) {
				if ( $this->is_main_products_loop_grid( $element ) ) {
					$element->add_render_attribute(
						'_wrapper',
						[
							'class' => 'fibofilters-elementor-products',
						]
					);

					do_action( 'fibofilters/front/display_horizontal_filters_placeholder' );
					do_action( 'fibofilters/front/display_mobile_filters_placeholder' );
					do_action( 'fibofilters/front/display_applied_filters_placeholder' );
				}
			}
		);

		add_filter(
			'elementor/frontend/widget/after_render',
			function ( $element ) {
				if ( $this->is_main_products_loop_grid( $element ) ) {
					do_action( 'fibofilters/front/display_load_more_button_placeholder' );
				}

				if ( ! empty( $GLOBALS['fibofilters_loop_grid_ordering_active'] ) ) {
					/** @var \WC_Query $fibofilters_loop_grid_wc_query */
					global $fibofilters_loop_grid_wc_query;

					if ( $fibofilters_loop_grid_wc_query instanceof \WC_Query ) {
						$fibofilters_loop_grid_wc_query->remove_ordering_args();
					}
					unset( $GLOBALS['fibofilters_loop_grid_ordering_active'], $fibofilters_loop_grid_wc_query );
				}
			}
		);

		/**
		 * ╭───────────────────╮
		 * | Products selector |
		 * ╰───────────────────╯
		 *
		 * Loop Grid uses different CSS classes for products wrapper.
		 */
		add_filter(
			'fibofilters/config/products_loop_selectors',
			function ( $selectors ) {

				$selectors[] = '.fibofilters-elementor-products .elementor-loop-container';

				return $selectors;
			}
		);

		/**
		 * ╭───────────────────╮
		 * | Products per page |
		 * ╰───────────────────╯
		 * An user might set the different value in the grid loop settings.
		 */

		if ( ! empty( $settings['posts_per_page'] ) ) {
			add_filter(
				'fibofilters/config/products_per_page',
				function () use ( $settings ): int {
					return (int) $settings['posts_per_page'];
				},
				15
			);
		}

		/**
		 * ╭─────────────────────╮
		 * | Pagination strategy |
		 * ╰─────────────────────╯
		 * An user might set the different value in the grid loop settings.
		 */

		if ( ! empty( $settings['pagination_type'] ) ) {
			$pagination_strategy = '';
			switch ( $settings['pagination_type'] ) {
				case 'load_more_on_click':
					$pagination_strategy = 'show-more-button';
					break;
				case 'numbers':
				case 'numbers_and_prev_next':
					$pagination_strategy = 'pagination';
					break;
				case 'load_more_infinite_scroll':
					$pagination_strategy = 'infinite-scroll';
					break;
			}
		}

		if ( ! empty( $pagination_strategy ) ) {
			add_filter(
				'fibofilters/config/pagination_strategy',
				function () use ( $pagination_strategy ): string {
					return $pagination_strategy;
				},
				15
			);
		}

		/**
		 * ╭─────────────────────╮
		 * | Product placeholder |
		 * ╰─────────────────────╯
		 */
		add_filter(
			'fibofilters/request/html/product_placeholder',
			function () {
				ob_start();
				?>
				<div class="product fibofilters-product-placeholder">
					<div>
						<img src="<?php echo esc_url( wc_placeholder_img_src() ); ?> " alt="Placeholder image"/>
					</div>
				</div>
				<?php
				return (string) ob_get_clean();
			}
		);

		/**
		 * ╭────────────────────────────────╮
		 * | "Show more product" as button  |
		 * ╰────────────────────────────────╯
		 */
		add_filter( 'fibofilters/config/show_more_as_button', '__return_true' );

		/**
		 * ╭──────────────────╮
		 * | Pagination args  |
		 * ╰──────────────────╯
		 */
		add_filter(
			'fibofilters/config/pagination_args',
			function ( $args ) {
				return wp_parse_args(
					[
						'type' => 'plain',
					],
					$args
				);
			}
		);

		/**
		 * ╭─────────────────────────────────────────────────────╮
		 * | Support for WooCommerce ordering in Loop Grid query |
		 * ╰─────────────────────────────────────────────────────╯
		 */
		add_action(
			'pre_get_posts',
			function ( \WP_Query $query ) {
				/** @var \WC_Query $fibofilters_loop_grid_wc_query */
				global $fibofilters_loop_grid_wc_query;

				if (
					$query->get( 'wc_query' ) === 'product_query' &&
					Helpers::is_running_inside_class( 'ElementorPro\Modules\QueryControl\Classes\Elementor_Post_Query', 40 )
				) {
					$context = apply_filters( 'fibofilters/request/get_context', [] );
					if ( isset( $context['show_filters'] ) && $context['show_filters'] ) {
						$query->set( 'fibofilters_loop_grid_ordering_applied', true );

						/**
						 * For unknown reason, when in catalog view, there is ordering by price DESC by default, it doesn't apply to the query in the Loop Grid widget.
						 * In this case, we need to pass this ordering manually to \WC_Query::get_catalog_ordering_args() method.
						 */
						$orderby = '';
						$order   = '';
						// phpcs:ignore WordPress.Security.NonceVerification.Recommended
						if ( ! isset( $_GET['orderby'] ) ) {
							$orderby_value = wc_clean( get_query_var( 'orderby' ) );
							$order_value   = wc_clean( get_query_var( 'order' ) );

							if ( $orderby_value === 'price' && $order_value === 'DESC' ) {
								$orderby = $orderby_value;
								$order   = $order_value;
							}
						}

						/**
						 * Calling this method on a WC_Query object will cause subsequent WP_Query to support
						 * WooCommerce-specific sorting, e.g. by price.
						 */
						$fibofilters_loop_grid_wc_query = new \WC_Query();
						$fibofilters_loop_grid_wc_query->get_catalog_ordering_args( $orderby, $order );
					}
				}
			}
		);

		/**
		 * ╭─────────────────────────────────────────────────────────────────────────╮
		 * | Removing support for WooCommerce sorting added with the previous filter |
		 * ╰─────────────────────────────────────────────────────────────────────────╯
		 */
		add_action(
			'loop_end',
			function ( $query ) {
				/** @var \WC_Query $fibofilters_loop_grid_wc_query */
				global $fibofilters_loop_grid_wc_query;

				if ( $query->get( 'fibofilters_loop_grid_ordering_applied' ) === true ) {
					$fibofilters_loop_grid_wc_query->remove_ordering_args();
				}
			}
		);

		$source = $settings['product_query_post_type'] ?? '';

		if ( $source === 'product' && $settings['fibofilters_integration'] === 'yes' ) {
			$context = $this->integrate_with_loop_grid_widget_others_source( $settings, $context );
		}

		return [ $context, $query_vars ];
	}

	private function integrate_with_loop_grid_widget_others_source( $settings, $context ): array {
		$orderby = $settings['product_query_orderby'] ?? 'date';
		$order   = $settings['product_query_order'] ?? 'DESC';

		if ( $orderby === 'date' ) {
			$orderby = 'date ID';
		}

		if ( $orderby === 'price' || $orderby === 'popularity' || $orderby === 'rating' ) {
			global $fibofilters_loop_grid_wc_query;
			$fibofilters_loop_grid_wc_query = new \WC_Query();
			$fibofilters_loop_grid_wc_query->get_catalog_ordering_args( $orderby, $order );

			$GLOBALS['fibofilters_loop_grid_ordering_active'] = true;
		}

		$context['internal']['forced_query_args']['orderby'] = $orderby;
		$context['internal']['forced_query_args']['order']   = $order;

		add_filter(
			'elementor/query/query_args',
			function ( $args ) {
				// Single products request.
				$single_product_ids = apply_filters( 'fibofilters/request/get_single_product_ids', [] );
				if ( ! empty( $single_product_ids ) ) {
					$args['post__in']       = $single_product_ids;
					$args['tax_query']      = [];
					$args['meta_query']     = [];
					$args['posts_per_page'] = - 1;
				}

				// Request with active filters.
				$filtered_products_ids = apply_filters( 'fibofilters/request/filtered_product_ids', [] );
				if ( ! empty( $filtered_products_ids ) ) {
					$args['post__in'] = $filtered_products_ids;
				}

				if ( get_query_var( 'paged' ) ) {
					$args['paged'] = get_query_var( 'paged' );
				}

				return $args;
			},
			15,
			2
		);

		add_filter( 'fibofilters/request/single_products/break_early', '__return_true' );

		return $context;
	}

	public function add_fibofilters_switch_to_woocommerce_loop_grid( $element ) {
		$element->add_control(
			'fibofilters_integration',
			[
				'label'     => _x( 'Integrate with FiboFilters', '[admin]', 'fibofilters' ),
				'type'      => \Elementor\Controls_Manager::SWITCHER,
				'default'   => '',
				'condition' => [
					'product_query_post_type!' => 'current_query',
				],
			]
		);
	}

	/**
	 * Check if specific Elementor widget is the Loop Grid element, and it's main products loop.
	 *
	 * @param $element
	 *
	 * @return bool
	 */
	private function is_main_products_loop_grid( $element ) {
		return is_object( $element ) && is_a( $element, 'ElementorPro\Modules\LoopBuilder\Widgets\Loop_Grid' );
	}

	/**
	 * Adding your own CSS class to the beginning of the product loop
	 *
	 * Thanks to this trick, we can clearly indicate which list contains the products
	 * that are to be displayed as the filter result.
	 *
	 * @param string $loop Loop HTML.
	 *
	 * @return string
	 */
	public function add_own_class_to_product_loop_start( string $loop ): string {
		$conditions_manager = \ElementorPro\Plugin::instance()->modules_manager->get_modules( 'theme-builder' )->get_conditions_manager();
		$documents          = $conditions_manager->get_documents_for_location( 'archive' );
		if ( empty( $documents ) ) {
			return $loop;
		}

		if (
			Helpers::is_running_inside_class( 'FiboFilters\Filtering\Request' ) ||
			Helpers::is_running_inside_class( 'ElementorPro\Modules\Woocommerce\Widgets\Products' )
		) {
			$loop = str_replace( 'class="products', 'class="products fibofilters-products-loop', $loop );
		}

		return (string) $loop;
	}

	/**
	 * Get info about Elementor templates that might include Product Loop Grid Widgets.
	 *
	 * @return array
	 */
	public function get_templates_with_product_loop_grid(): array {
		global $wpdb;

		if ( ! is_null( $this->loop_grid_templates ) ) {
			return $this->loop_grid_templates;
		}

		$templates = [];

		$sql = $wpdb->prepare(
			"
				SELECT DISTINCT ID as template_id,
					(SELECT meta_value
					FROM $wpdb->postmeta
					WHERE post_id = template_id
					AND meta_key='_elementor_data'
					LIMIT 1) AS elementor_data
				FROM $wpdb->posts
				WHERE post_type = 'elementor_library'
				AND post_status = 'publish'
				HAVING elementor_data IS NOT NULL
				AND elementor_data LIKE '%\"product_query_post_type\":\"current_query\"%';
			"
		);

		$res = $wpdb->get_results( $sql, ARRAY_A );

		if ( ! empty( $res ) && is_array( $res ) ) {
			foreach ( $res as $template ) {

				if ( empty( $template['elementor_data'] ) ) {
					continue;
				}

				$template_data = json_decode( $template['elementor_data'], true );

				if ( json_last_error() !== JSON_ERROR_NONE || ! is_array( $template_data ) ) {
					continue;
				}

				$template_data = $this->extract_loop_grid_templates( $template_data );

				$templates = array_merge( $templates, $template_data );
			}
		}

		$this->loop_grid_templates = $templates;

		return $templates;
	}

	/**
	 * Extract everything what we need from the '_elementor_data' field.
	 *
	 * @param array $template_data Source of the data.
	 *
	 * @return array
	 */
	private function extract_loop_grid_templates( array $template_data ): array {
		$templates = [];

		$iterator  = new \RecursiveArrayIterator( $template_data );
		$recursive = new \RecursiveIteratorIterator(
			$iterator,
			\RecursiveIteratorIterator::SELF_FIRST
		);

		foreach ( $recursive as $key => $value ) {
			if ( $key === 'elements' && ! empty( $value ) ) {
				$i = 0;
				foreach ( $value as $element ) {
					if (
						! empty( $element['widgetType'] ) && $element['widgetType'] === 'loop-grid'
						&& ! empty( $element['settings']['_skin'] ) && $element['settings']['_skin'] === 'product'
						&& ! empty( $element['settings']['product_query_post_type'] ) && $element['settings']['product_query_post_type'] === 'current_query'
					) {

						$template_id = ! empty( $element['settings']['template_id'] ) ? (int) $element['settings']['template_id'] : 0;

						$templates[ $i ] = [
							'template_id' => $template_id,
						];

						$i++;
					}
				}
			}
		}

		return $templates;
	}

	/**
	 * Add "Integrate with FiboFilters" switch in "Products" widget
	 *
	 * @param Products $element Elementor widget.
	 */
	public function add_fibofilters_switch_to_woocommerce_products_widget( $element ): void {
		$element->add_control(
			'fibofilters_integration',
			[
				'label'     => _x( 'Integrate with FiboFilters', '[admin]', 'fibofilters' ),
				'type'      => \Elementor\Controls_Manager::SWITCHER,
				'default'   => '',
				'condition' => [
					'query_post_type!' => 'current_query',
				],
			]
		);
	}

	/**
	 * @param array     $args Context and query vars.
	 * @param \WP_Query $query Main query.
	 */
	public function support_page_with_products( array $args, \WP_Query $query ): array {
		if ( ! class_exists( '\Elementor\Plugin' ) ) {
			return $args;
		}

		list ($context, $query_vars ) = $args;

		// Break early if filters are already displayed.
		if ( $context['show_filters'] ) {
			return $args;
		}

		// Break early if WP_Query isn't set.
		if ( empty( $query->queried_object->ID ) ) {
			return $args;
		}

		$elementor = Plugin::instance();
		$document  = $elementor->documents->get_doc_for_frontend( $query->queried_object->ID );
		if ( empty( $document ) || ! $document->is_built_with_elementor() ) {
			return $args;
		}

		$elements_data = $document->get_elements_data();
		$widget_data   = $this->get_elementor_widget_data( $elements_data, 'woocommerce-products' );

		if ( empty( $widget_data ) ) {
			return $args;
		}

		$instance = $elementor->elements_manager->create_element_instance( $widget_data );
		$settings = $instance->get_settings_for_display();

		$shortcode_object = Products::get_shortcode_object( $settings );
		$query_vars       = $shortcode_object->get_query_args();

		$context['show_filters'] = true;
		$context['internal']['is_page_with_elementor_woocommerce_products'] = true;
		$context['internal']['forced_query_args']                           = [];

		if ( ! empty( $query_vars['posts_per_page'] ) && $query_vars['posts_per_page'] > 0 ) {
			$context['internal']['forced_query_args']['posts_per_page'] = $query_vars['posts_per_page'];

			if ( empty( $settings['paginate'] ) ) {
				$context['internal']['forced_query_args']['nopaging'] = false;
			}

			/*
			 * ╭───────────────────────────╮
			 * | Config: products per page |
			 * ╰───────────────────────────╯
			 */
			add_filter(
				'fibofilters/config/products_per_page',
				function () use ( $query_vars ) {
					return $query_vars['posts_per_page'];
				}
			);
		}

		/*
		 * ╭─────────────────────────────────────╮
		 * | Products - add CSS class to wrapper |
		 * ╰─────────────────────────────────────╯
		 */
		add_filter(
			'elementor/frontend/widget/before_render',
			function ( $element ) {
				if ( $element->get_name() === 'woocommerce-products' && $element->get_settings_for_display( 'fibofilters_integration' ) === 'yes' ) {
					$element->add_render_attribute(
						'_wrapper',
						[
							'class' => 'fibofilters-elementor-products',
						]
					);
				}
			}
		);

		/*
		 * ╭───────────────────────────────────────╮
		 * | Config: adjust products loop selector |
		 * ╰───────────────────────────────────────╯
		 */
		add_filter(
			'fibofilters/config/products_loop_selectors',
			function ( $selectors ) {
				$selectors[] = '.fibofilters-elementor-products ul.products';

				return $selectors;
			}
		);

		/*
		 * ╭────────────────────────────────────────╮
		 * | Config: "show more products" as button |
		 * ╰────────────────────────────────────────╯
		 */
		add_filter( 'fibofilters/config/show_more_as_button', '__return_true' );

		/*
		 * ╭───────────────────────────────────────────────────────────╮
		 * | Config: set fetch URL for single products to current page |
		 * ╰───────────────────────────────────────────────────────────╯
		 */
		add_filter( 'fibofilters/config/single_products_fetch_url', fn() => get_permalink( $query->queried_object->ID ) );

		return [ $context, $query_vars ];
	}

	/**
	 * Search for specific widget in Elementor data
	 *
	 * @param array  $elements Widget data.
	 * @param string $widget Widget name.
	 */
	private function get_elementor_widget_data( $elements, $widget ): array {
		$result = [];

		if ( ! is_array( $elements ) || empty( $elements ) || empty( $widget ) ) {
			return [];
		}

		if (
			isset( $elements['widgetType'] ) &&
			$elements['widgetType'] === $widget &&
			isset( $elements['settings']['fibofilters_integration'] ) &&
			$elements['settings']['fibofilters_integration'] === 'yes'
		) {
			return $elements;
		}

		// Plain array of elements.
		if ( ! isset( $elements['elements'] ) ) {
			foreach ( $elements as $element ) {
				$result_tmp = $this->get_elementor_widget_data( $element, $widget );
				if ( ! empty( $result_tmp ) ) {
					$result = $result_tmp;
				}
			}
		} elseif ( is_array( $elements['elements'] ) && ! empty( $elements['elements'] ) ) {
			// Assoc array - single element.
			$result_tmp = $this->get_elementor_widget_data( $elements['elements'], $widget );
			if ( ! empty( $result_tmp ) ) {
				$result = $result_tmp;
			}
		}

		return $result;
	}
}
