<?php
declare( strict_types=1 );

namespace FiboFilters\Integrations\Themes;

use Bricks\Database;
use Bricks\Elements;
use Bricks\Helpers;
use FiboFilters\Config\Env;

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

/**
 * Class Bricks
 */
class Bricks extends AbstractTheme {
	public function init( string $slug = '', string $name = '', array $args = [] ): void {
		parent::init( $slug, $name, $args );

		if ( $this->is_integration_enabled() ) {
			add_action( 'init', [ $this, 'register_elements' ], 11 );
			add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] );

			add_filter( 'bricks/elements/container/control_groups', [ $this, 'add_fibofilters_control_group' ] );
			add_filter( 'bricks/elements/section/control_groups', [ $this, 'add_fibofilters_control_group' ] );
			add_filter( 'bricks/elements/block/control_groups', [ $this, 'add_fibofilters_control_group' ] );
			add_filter( 'bricks/elements/div/control_groups', [ $this, 'add_fibofilters_control_group' ] );

			add_filter( 'bricks/elements/container/controls', [ $this, 'add_fibofilters_products_loop_control' ] );
			add_filter( 'bricks/elements/section/controls', [ $this, 'add_fibofilters_products_loop_control' ] );
			add_filter( 'bricks/elements/block/controls', [ $this, 'add_fibofilters_products_loop_control' ] );
			add_filter( 'bricks/elements/div/controls', [ $this, 'add_fibofilters_products_loop_control' ] );

			add_filter( 'bricks/elements/block/controls', [ $this, 'add_fibofilters_products_loop_item_control' ] );
			add_filter( 'bricks/elements/div/controls', [ $this, 'add_fibofilters_products_loop_item_control' ] );

			add_action( 'wp', [ $this, 'maybe_init_custom_query_integration' ], PHP_INT_MAX - 5 );
		}
	}

	public function add_fibofilters_control_group( $control_groups ) {
		return array_merge(
			$control_groups,
			[
				'fibofilters' => [
					'title' => esc_html_x( 'FiboFilters', '[admin]', 'fibofilters' ),
					'tab'   => 'content',
				],
			]
		);
	}

	public function add_fibofilters_products_loop_control( $controls ): array {
		return array_merge(
			$controls,
			[
				'fibofilters_products_loop' => [
					'tab'    => 'content',
					'group'  => 'fibofilters',
					'label'  => esc_html_x( 'Mark this element as a container for products', '[admin]', 'fibofilters' ),
					'type'   => 'checkbox',
					'inline' => true,
				],
			]
		);
	}

	public function add_fibofilters_products_loop_item_control( $controls ): array {
		return array_merge(
			$controls,
			[
				'fibofilters_products_loop_item' => [
					'tab'      => 'content',
					'group'    => 'fibofilters',
					'label'    => esc_html_x( 'Mark this element as repeatable product item', '[admin]', 'fibofilters' ),
					'type'     => 'checkbox',
					'inline'   => true,
					'required' => [
						[ 'hasLoop', '=', true ],
					],
				],
			]
		);
	}

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

	public function register_elements(): void {
		if ( ! class_exists( '\Bricks\Elements' ) ) {
			return;
		}

		Elements::register_element( __DIR__ . '/Bricks/FiboFiltersElement.php', 'fibofilters-filters' );
		Elements::register_element( __DIR__ . '/Bricks/FiboFiltersAppliedFiltersElement.php', 'fibofilters-applied-filters' );
		Elements::register_element( __DIR__ . '/Bricks/FiboFiltersInfiniteScrollTriggerElement.php', 'fibofilters-infinite-scroll-trigger' );
		Elements::register_element( __DIR__ . '/Bricks/FiboFiltersShowMoreProductsBtnElement.php', 'fibofilters-show-more-products-btn' );
		Elements::register_element( __DIR__ . '/Bricks/FiboFiltersShowPreviousProductsBtnElement.php', 'fibofilters-show-previous-products-btn' );
	}

	/**
	 * Initialize integration with Bricks products loops
	 *
	 * We have two different types of products loops in Bricks:
	 * 1. Products element
	 *    We check if "Products" element is used on the page and set appropriate filters for FiboFilters.
	 *
	 * 2. Custom loop created with Bricks elements
	 *    After fetching data from Bricks, we check if there are elements that are marked
	 *    as a container for a product list or a product in a loop. If so, the appropriate
	 *    filters are set for FiboFilters and in Bricks.
	 */
	public function maybe_init_custom_query_integration(): void {
		$context = apply_filters( 'fibofilters/request/get_context', [] );
		// Break if filters won't be displayed and it's not a request for products.
		if ( empty( $context['show_filters'] ) && empty( $context['is_get_products'] ) ) {
			return;
		}

		$post_id = $context['conditions']['is_shop'] ? wc_get_page_id( 'shop' ) : 0;
		$data    = Helpers::get_bricks_data( $post_id, 'content' );

		if ( empty( $data ) || ! is_array( $data ) ) {
			return;
		}

		foreach ( $data as $element ) {
			if ( $element['name'] === 'woocommerce-products' ) {
				/**
				 * 1. "Products" element.
				 */
				// Products per page.
				if ( ! empty( intval( $element['settings']['posts_per_page'] ) ) ) {
					add_filter( 'fibofilters/config/products_per_page', fn() => intval( $element['settings']['posts_per_page'] ) );
				}

				// Products per row.
				if ( ! empty( intval( $element['settings']['columns'] ) ) ) {
					add_filter( 'fibofilters/config/products_per_row', fn() => intval( $element['settings']['columns'] ) );
				}

				// Products fetching strategy.
				add_filter( 'fibofilters/config/products_fetching_strategy', fn() => 'page' );

				// Products per page while getting single products.
				add_filter(
					'bricks/posts/query_vars',
					function ( $query_vars, $settings, $element_id, $element_name ) use ( $context ) {
						if ( $element_name === 'woocommerce-products' && ! empty( $context['is_get_products'] ) ) {
							$query_vars['posts_per_page'] = - 1;
						}

						return $query_vars;
					},
					10,
					4
				);
			} elseif ( isset( $element['settings']['fibofilters_products_loop'] ) && $element['settings']['fibofilters_products_loop'] ) {
				/**
				 * 2a. Container for products loop.
				 */

				// Custom products loop selector.
				add_filter( 'fibofilters/config/products_loop_selectors', fn() => [ '#brxe-' . $element['id'] ] );

				add_filter( 'bricks/element/set_root_attributes', function ( $attributes, $element ) {
					if ( ! empty( $element->settings['fibofilters_products_loop'] ) && empty( $attributes['id'] ) ) {
						$attributes['id'] = $element->get_element_attribute_id();
					}

					return $attributes;
				}, 10, 2 );
			} elseif ( isset( $element['settings']['fibofilters_products_loop_item'] ) && $element['settings']['fibofilters_products_loop_item'] ) {
				/**
				 * 2b. Product item in a loop.
				 */

				// Product placeholder.
				$this->set_product_placeholder( $element['settings']['tag'] ?? 'div' );

				// Products per page.
				$posts_per_page = ! empty( intval( $element['settings']['query']['posts_per_page'] ) ) ? intval( $element['settings']['query']['posts_per_page'] ) : 10;
				add_filter( 'fibofilters/config/products_per_page', fn() => $posts_per_page );

				// Add CSS classes to product item.
				$this->bricks_add_css_classes_to_product_item();

				// Products fetching strategy.
				add_filter( 'fibofilters/config/products_fetching_strategy', fn() => 'page' );

				// Support for no results template.
				if ( ! empty( $element['settings']['query']['no_results_template'] ) ) {
					// Exclude no results template from removing from products container.
					add_filter(
						'fibofilters/config/clear_product_container_exceptions',
						function ( $exceptions ) {
							$exceptions .= ':not(.bricks-posts-nothing-found)';

							return $exceptions;
						}
					);

					// Enqueue script to show/hide no results template.
					$this->show_or_hide_no_results_template();
				}
			}
		}
	}

	private function set_product_placeholder( $tag = 'div' ) {
		add_filter(
			'fibofilters/request/html/product_placeholder',
			function () use( $tag ) {
				ob_start();
				?>
				<<?php echo esc_attr( $tag ); ?> class="product fibofilters-product-placeholder">
					<div>
						<img src="<?php echo esc_url( wc_placeholder_img_src() ); ?> " alt="Placeholder image"/>
					</div>
				</<?php echo esc_attr( $tag ); ?>>
				<?php
				return (string) ob_get_clean();
			}
		);
	}

	private function bricks_add_css_classes_to_product_item(): void {
		add_filter(
			'bricks/element/render_attributes',
			function ( $attributes, $key, $element ) {
				if ( $key === '_root' && isset( $element->settings['fibofilters_products_loop_item'] ) && $element->settings['fibofilters_products_loop_item'] && isset( $element->post_id ) ) {
					$attributes['_root']['class'][] = 'product';
					$attributes['_root']['class'][] = 'post-' . $element->post_id;
				}

				return $attributes;
			},
			10,
			3
		);
	}

	private function show_or_hide_no_results_template() {
		add_action(
			'wp_enqueue_scripts',
			function () {
				ob_start();
				?>
				<script>
					if (typeof fiboFilters !== 'undefined') {
						fiboFilters.hooks.addAction('fiboFilters.renderer.no_results', 'fibofilters', function() {
							const fiboFiltersBricksNothingFound = document.querySelector('.bricks-posts-nothing-found');
							if (fiboFiltersBricksNothingFound) {
								fiboFiltersBricksNothingFound.style.display = 'block';
							}
						});

						function fibofiltersBricksHideNoResults() {
							const fiboFiltersBricksNothingFound = document.querySelector('.bricks-posts-nothing-found');
							if (fiboFiltersBricksNothingFound) {
								fiboFiltersBricksNothingFound.style.display = 'none';
							}
						}
						fiboFilters.hooks.addAction('fiboFilters.renderer.products_loaded', 'fibofilters', fibofiltersBricksHideNoResults);
						fiboFilters.hooks.addAction('fiboFilters.renderer.product_placeholders_overwritten', 'fibofilters', fibofiltersBricksHideNoResults);
					}
				</script>
				<?php
				$this->enqueue_inline_script( (string) ob_get_clean() );
			}
		);
	}
}
