<?php
/**
 * Taxonomy facet type
 *
 * @since 4.3.0
 * @package elasticpress
 */

namespace ElasticPress\Feature\Facets;

/**
 * Abstract Facet type class
 *
 * Keeping this as an abstract class (and not an interface) to make
 * the implementation of common methods easier.
 */
abstract class FacetType {

	/**
	 * Setup hooks and filters for feature
	 */
	abstract public function setup();

	/**
	 * Get the facet filter name.
	 *
	 * @return string The filter name.
	 */
	abstract public function get_filter_name(): string;

	/**
	 * Get the facet filter type.
	 *
	 * @return string The filter name.
	 */
	abstract public function get_filter_type(): string;

	/**
	 * Get the facet sanitize function.
	 *
	 * @return string The function name.
	 */
	public function get_sanitize_callback(): string {

		/**
		 * Filter the facet filter sanitize callback.
		 *
		 * @hook ep_facet_default_sanitize_callback
		 * @since 4.4.0
		 * @param   {string} Facet filter sanitize callback
		 * @return  {string} New facet filter sanitize callback
		 */
		return apply_filters( 'ep_facet_default_sanitize_callback', 'sanitize_text_field' );
	}

	/**
	 * Format selected values.
	 *
	 * @since 4.5.0
	 * @param string $facet   Facet name
	 * @param mixed  $value   Facet value
	 * @param array  $filters Selected filters
	 * @return array
	 */
	public function format_selected( string $facet, $value, array $filters ) {
		$terms = explode( ',', trim( $value, ',' ) );
		$filters[ $this->get_filter_type() ][ $facet ] = [
			'terms' => array_fill_keys( array_map( $this->get_sanitize_callback(), $terms ), true ),
		];
		return $filters;
	}

	/**
	 * Add selected filters to the query string.
	 *
	 * @since 4.5.0
	 * @param array $query_params Existent query parameters
	 * @param array $filters      Selected filters
	 * @return array
	 */
	public function add_query_params( array $query_params, array $filters ): array {
		$selected = $filters[ $this->get_filter_type() ];

		foreach ( $selected as $facet => $filter ) {
			if ( ! empty( $filter['terms'] ) ) {
				$query_params[ $this->get_filter_name() . $facet ] = implode( ',', array_keys( $filter['terms'] ) );
			}
		}

		return $query_params;
	}

	/**
	 * Get all facet fields selected across all blocks of the current facet type.
	 *
	 * Given a block name, e.g., `elasticpress/facet-meta` this method returns all meta fields
	 * selected in all blocks.
	 *
	 * @param string $block_name The block name
	 * @return array
	 */
	protected function block_template_meta_fields( string $block_name ): array {
		$block_template_utils = \ElasticPress\get_container()->get( '\ElasticPress\BlockTemplateUtils' );
		$ep_blocks            = $block_template_utils->get_specific_block_in_all_templates( $block_name );

		return array_filter(
			array_reduce(
				$ep_blocks,
				function ( $acc, $block ) use ( $block_name ) {
					if ( 0 !== strpos( $block['blockName'], $block_name ) ) {
						return $acc;
					}

					if ( empty( $block['attrs']['facet'] ) ) {
						return $acc;
					}

					$acc[] = $block['attrs']['facet'];
					return $acc;
				},
				[]
			)
		);
	}

	/**
	 * Get all meta fields selected in all elementor widgets.
	 *
	 * @param string $widget_name The widget name, e.g., `wp-widget-ep-facet-meta`
	 * @return array
	 */
	protected function elementor_template_meta_fields( string $widget_name ): array {
		$elementor_utils = \ElasticPress\get_container()->get( '\ElasticPress\ElementorUtils' );
		$ep_widgets      = $elementor_utils->get_specific_widget_in_all_templates( $widget_name );

		// Early return if no widgets found
		if ( empty( $ep_widgets ) ) {
			return [];
		}

		$meta_fields = [];
		foreach ( $ep_widgets as $widget ) {
			if ( $widget['widgetType'] !== $widget_name ) {
				continue;
			}

			// Skip if facet setting is empty
			if ( empty( $widget['settings']['wp']['facet'] ) ) {
				continue;
			}

			$meta_fields[] = $widget['settings']['wp']['facet'];
		}

		return array_filter( $meta_fields );
	}
}
