<?php
declare( strict_types=1 );

namespace FiboFilters\Integrations\Plugins;

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\Elementor\Utils as ElementorUtils;
use FiboFilters\Settings\Settings;
use FiboFilters\Util\Helpers;
use FiboFilters\WooCommerce\Helper as WooCommerceHelper;

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

/**
 * Class EssentialAddonsForElementor
 *
 * Plugin Name: Essential Addons for Elementor
 * Plugin URI: https://wordpress.org/plugins/essential-addons-for-elementor-lite/
 * Tested versions: 6.1.9
 *
 * @see wp-content/plugins/essential-addons-for-elementor-lite/includes/Elements/Product_Grid.php - Woo Product Grid
 */
class EssentialAddonsForElementor extends AbstractPlugin {

	/** @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 {
		$this->register_settings();

		add_filter( 'fibofilters/request/context_and_query_vars', [ $this, 'support_woo_product_grid_widget' ], 15, 2 );

		add_action(
			'elementor/element/eicon-woocommerce/eael_section_product_grid_settings/before_section_end',
			[
				$this,
				'add_fibofilters_switch_to_woo_product_grid_widget',
			],
			10,
			2
		);
	}


	public function support_woo_product_grid_widget( array $args, \WP_Query $query ): array {
		if ( ! class_exists( '\Elementor\Plugin' ) ) {
			return $args;
		}

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

		$support_for_woo_product_grid = $this->settings->get( 'integrations_essential_addons_for_elementor_woo_product_grid_widget_support' );

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

		// Break early if products are displayed in by "Products" widget.
		if ( ! empty( $context['internal']['is_page_with_elementor_woocommerce_products'] ) ) {
			return $args;
		}

		if ( ! empty( $query->queried_object->ID ) ) {
			$element = $this->elementor_utils->get_element_for_integrate_with_it_on_single( 'eicon-woocommerce', $query->queried_object->ID, true );

			// Run integration for single post/page with Woo Product Grid widget.
			if ( ! empty( $element ) ) {
				$context['show_filters'] = true;

				$settings   = $element->get_active_settings();
				$query_vars = $element->build_product_query( $settings );

				// Load more >> Load more: Disable.
				if ( $settings['show_load_more'] === 'no' ) {
					$context['internal']['forced_query_args']                   = [];
					$context['internal']['forced_query_args']['posts_per_page'] = $settings['eael_product_grid_products_count'] ?? 12;
					$context['internal']['forced_query_args']['nopaging']       = false;
				}

				$this->integrate_with_fibofilters_on_single_page( $element, $query->queried_object->ID );
			}
		} else {
			/** @var \Essential_Addons_Elementor\Elements\Product_Grid $element */
			$element = $this->elementor_utils->get_element_for_integrate_with_it_on_archive( 'eicon-woocommerce' );
		}
		if ( empty( $element ) ) {
			return $args;
		}

		$this->integrate_with_fibofilters( $element );

		return [ $context, $query_vars ];
	}

	private function integrate_with_fibofilters_on_single_page( $element, $queried_object_id ): void {
		$settings = $element->get_active_settings();

		add_filter( 'fibofilters/config/single_products_fetch_url', fn() => get_permalink( $queried_object_id ) );

		// Single products will be returned in this integration via Woo Product Grid widget.
		add_filter( 'fibofilters/request/single_products/break_early', '__return_true' );

		/**
		 * ╭───────────────────────────╮
		 * | Config: products per page |
		 * ╰───────────────────────────╯
		 */
		if ( isset( $settings['eael_product_grid_products_count'] ) && is_numeric( $settings['eael_product_grid_products_count'] ) ) {
			add_filter( 'fibofilters/config/products_per_page', fn() => intval( $settings['eael_product_grid_products_count'] ), 15 );
		}

		/**
		 * ╭───────────────────╮
		 * | Custom CSS and JS |
		 * ╰───────────────────╯
		 */
		if ( $settings['show_load_more'] === 'true' ) {
			ob_start();
			// Hide "Load more" button.
			?>
			<style>
				.elementor-element-<?php echo esc_js( $element->get_id() ); ?> .eael-load-more-button-wrap {
					display: none;
				}
			</style>
			<?php
			$this->enqueue_inline_style( ob_get_clean() );
		}

		if ( $settings['show_load_more'] === 'infinity' ) {
			// Hide infinity scroll trigger.
			ob_start();
			?>
			<style>
				.elementor-element-<?php echo esc_js( $element->get_id() ); ?> .eael-infinity-scroll {
					display: none;
				}
			</style>
			<?php
			$this->enqueue_inline_style( ob_get_clean() );

			ob_start();
			// Remove infinity scroll trigger.
			?>
			<script>
				const fiboFiltersWooProductGridInfinityScroll = document.querySelector('.elementor-element-<?php echo esc_js( $element->get_id() ); ?> .eael-infinity-scroll');
				if (fiboFiltersWooProductGridInfinityScroll) {
					fiboFiltersWooProductGridInfinityScroll.remove();
				}
			</script>
			<?php
			$this->enqueue_inline_script( (string) ob_get_clean(), [], 'woo-product-grid' );
		}
	}

	private function integrate_with_fibofilters( $element ): void {
		$settings = $element->get_active_settings();

		add_action( 'eael_woo_before_product_loop', [ $this->front, 'display_horizontal_filters_placeholder' ], 500 );
		add_action( 'eael_woo_before_product_loop', [ $this->front, 'display_mobile_filters_placeholder' ], 510 );
		add_action( 'eael_woo_before_product_loop', [ $this->front, 'display_applied_filters_placeholder' ], 520 );
		add_action( 'eael_woo_before_product_loop', [ $this->front, 'display_load_previous_button_placeholder' ], 520 );

		add_action(
			'eael_woo_after_product_loop',
			function ( $eael_product_grid_style_preset ) {
				if ( ! empty( $eael_product_grid_style_preset ) ) {
					$this->front->display_load_more_button_placeholder();
					$this->front->display_infinite_scroll_trigger();
				}
			}
		);

		/*
		 * ╭───────────────────────────────────────────╮
		 * | Set the IDs when fetching single products |
		 * ╰───────────────────────────────────────────╯
		 * Only for Woo Product Grid >> Product Settings >> Source: Products
		 */
		if ( $settings['post_type'] === 'product' ) {
			$single_product_ids = apply_filters( 'fibofilters/request/get_single_product_ids', [] );
			if ( ! empty( $single_product_ids ) ) {
				add_action(
					'pre_get_posts',
					function ( \WP_Query $query ) use ( $single_product_ids ) {
						if ( Helpers::is_running_inside_class( 'Essential_Addons_Elementor\Elements\Product_Grid' ) ) {
							$query->set( 'post__in', $single_product_ids );
							$query->set( 'tax_query', [] );
							$query->set( 'meta_query', [] );
							$query->set( 'posts_per_page', -1 );
						}
					}
				);
			}
		}

		/*
		 * ╭──────────────────────────╮
		 * | Config: products per row |
		 * ╰──────────────────────────╯
		 */
		if ( $settings['eael_product_grid_layout'] === 'list' ) {
			add_filter(
				'fibofilters/config/products_per_row',
				fn() => intval( $settings['eael_product_list_column'] ),
				15
			);
		} else {
			add_filter(
				'fibofilters/config/products_per_row',
				fn() => intval( $settings['eael_product_grid_column'] ),
				15
			);
		}

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

		/*
		 * ╭────────────────────────────────────╮
		 * | Config: products fetching strategy |
		 * ╰────────────────────────────────────╯
		 */
		add_filter( 'fibofilters/config/products_fetching_strategy', fn() => 'page', 15 );

		/**
		 * ╭───────────────────────────────────────╮
		 * | Add needed classes to product wrapper |
		 * ╰───────────────────────────────────────╯
		 */
		add_filter(
			'eael_product_wrapper_class',
			function ( $classes, $product_id ) {
				$classes[] = 'product';
				$classes[] = 'post-' . $product_id;

				return $classes;
			},
			10,
			2
		);

		/**
		 * ╭─────────────────────╮
		 * | Product placeholder |
		 * ╰─────────────────────╯
		 */
		add_filter(
			'fibofilters/request/html/product_placeholder',
			function () use ( $settings ) {
				ob_start();
				// Layout: list.
				if ( $settings['eael_product_grid_layout'] === 'list' ) {
					?>
					<li class="product fibofilters-product-placeholder">
						<div class="eael-product-wrap">
							<div class="product-image-wrap">
								<div class="image-wrap">
									<img src="<?php echo esc_url( wc_placeholder_img_src() ); ?> " alt="Placeholder image"/>
								</div>
							</div>
							<div class="product-details-wrap">
								<div class="eael-product-title"></div>
							</div>
						</div>
					</li>
					<?php
				} else {
					// Layout: grid, masonry.
					?>
					<li class="product fibofilters-product-placeholder">
						<img src="<?php echo esc_url( wc_placeholder_img_src() ); ?> " alt="Placeholder image"/>
					</li>
					<?php
				}
				return (string) ob_get_clean();
			},
			15
		);

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

		/**
		 * Widget uses Isotope for product layout: https://isotope.metafizzy.co/
		 * After filtering products, we need to reload Isotope layout including appended products.
		 */
		ob_start();
		?>
		<script>
			if (typeof fiboFilters !== 'undefined') {
				function fibofiltersIntegrationFix() {
					if (typeof jQuery === 'undefined') {
						return;
					}

					const scope = jQuery(".elementor-element-<?php echo esc_js( $element->get_id() ); ?>");
					const products = jQuery('.products', scope);
					const layoutMode = products.data('layout-mode');

					if (layoutMode === 'masonry') {
						const products = jQuery('#eael-product-grid .products');
						if (typeof products.data('isotope') !== 'undefined') {
							products.data('isotope').options.transitionDuration = 0;
							products.imagesLoaded().progress(function () {
								products.isotope('reloadItems').isotope('arrange');
							});
						}
					}
				}

				fiboFilters.hooks.addAction('fiboFilters.renderer.products_loaded', 'fibofilters', fibofiltersIntegrationFix);
				fiboFilters.hooks.addAction('fiboFilters.renderer.product_placeholders_overwritten', 'fibofilters', fibofiltersIntegrationFix);
			}
		</script>
		<?php
		$this->enqueue_inline_script( (string) ob_get_clean(), [ 'jquery' ], 'woo-product-grid-isotope' );
	}

	/**
	 * 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->elementor_utils->is_elementor_pro_active() ) {
			return;
		}

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

		add_filter(
			'fibofilters/settings/section=integrations',
			function ( array $settings ): array {
				$docs_url = esc_url( Env::$doc_url . 'plugin-integrations/essential-addons-for-elementor/' );
				/* translators: 1: Documentation URL */
				$head_desc = sprintf( _x( 'Options for integration with the %1$s plugin. A full description of the integration can be found in <a target="_blank" href="%2$s">the documentation</a>.', '[admin]', 'fibofilters' ), 'Essential Addons for Elementor', $docs_url );

				$woo_product_grid_docs_url = 'https://essential-addons.com/docs/woocommerce-product-grid/';
				$widget_name               = 'Woo Product Grid';

				$settings[20] = [
					'name'        => 'essential_addons_for_elementor_header',
					/* translators: 1: Version of  Essential Addons for Elementor */
					'label'       => sprintf( _x( 'Essential Addons for Elementor (v%s)', '[admin]', 'fibofilters' ), EAEL_PLUGIN_VERSION ),
					'description' => $head_desc,
					'type'        => 'header',
					'group'       => 'integration_essential_addons_for_elementor',
				];

				$settings[25] = [
					'name'        => 'essential_addons_for_elementor_woo_product_grid_widget_support',
					'type'        => 'toggle',
					/* translators: 1: Widget name */
					'label'       => sprintf( _x( 'Support for %s widget', '[admin]', 'fibofilters' ), $widget_name ),
					/* translators: 1: Documentation URL */
					'description' => sprintf( _x( 'If you use the <a href="%1$s" target="_blank">%2$s</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' ), $woo_product_grid_docs_url, $widget_name ),
					'default'     => false,
					'schema'      => [
						'type' => 'boolean',
					],
					'group'       => 'integration_essential_addons_for_elementor',
				];

				return $settings;
			}
		);
	}

	/**
	 * Add "Integrate with FiboFilters" switch in "Woo Product Grid" widget
	 *
	 * @param Products $element Elementor widget.
	 */
	public function add_fibofilters_switch_to_woo_product_grid_widget( $element ): void {
		$element->start_injection(
			[
				'at' => 'after',
				'of' => 'post_type',
			]
		);

		$element->add_control(
			'fibofilters_integration',
			[
				'label'     => _x( 'Integrate with FiboFilters', '[admin]', 'fibofilters' ),
				'type'      => \Elementor\Controls_Manager::SWITCHER,
				'default'   => '',
				'condition' => [
					'post_type' => 'product',
				],
			]
		);

		$element->end_injection();
	}
}
