<?php
/**
 * Post Type facet type
 *
 * @since 4.6.0
 * @package elasticpress
 */

namespace ElasticPress\Feature\Facets\Types\PostType;

use ElasticPress\Features;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Post Type facet type class
 */
class FacetType extends \ElasticPress\Feature\Facets\FacetType {
	/**
	 * Block instance.
	 *
	 * @var Block
	 */
	public $block;

	/**
	 * Setup hooks and filters for feature
	 */
	public function setup() {
		add_filter( 'ep_facet_query_filters', [ $this, 'add_query_filters' ] );
		add_filter( 'ep_facet_wp_query_aggs_facet', [ $this, 'set_wp_query_aggs' ] );

		$this->block = new Block();
		$this->block->setup();
	}

	/**
	 * Get the facet filter name.
	 *
	 * @return string The filter name.
	 */
	public function get_filter_name(): string {
		/**
		 * Filter the facet filter name that's added to the URL
		 *
		 * @hook ep_facet_post_type_filter_name
		 * @since 4.6.0
		 * @param   {string} Facet filter name
		 * @return  {string} New facet filter name
		 */
		return apply_filters( 'ep_facet_post_type_filter_name', 'ep_post_type_filter' );
	}

	/**
	 * Get the facet filter type.
	 *
	 * @return string The filter name.
	 */
	public function get_filter_type(): string {
		/**
		 * Filter the facet filter type. Used by the Facet feature to organize filters.
		 *
		 * Note: Do not set is as `post_type`, as it will conflict with the post_type query parameter if set.
		 *
		 * @hook ep_facet_post_type_filter_type
		 * @since 4.6.0
		 * @param   {string} Facet filter type
		 * @return  {string} New facet filter type
		 */
		return apply_filters( 'ep_facet_post_type_filter_type', 'ep_post_type' );
	}

	/**
	 * Add post type fields to facets aggs
	 *
	 * @param array $facet_aggs Facet Aggs array.
	 * @return array
	 */
	public function set_wp_query_aggs( $facet_aggs ) {
		$post_types = $this->get_facetable_post_types();

		if ( empty( $post_types ) ) {
			return $facet_aggs;
		}

		$facet_aggs['post_type'] = array(
			'terms' => array(
				/**
				 * Filter the number of different values (and their count) for post types returned by Elasticsearch.
				 *
				 * @since 4.6.0
				 * @hook ep_facet_post_type_size
				 * @param {int}    $size       The number of different values. Default: 10000
				 * @param {array} $post_types Post types
				 * @return {int} The new number of different values
				 */
				'size'  => apply_filters( 'ep_facet_post_type_size', 10000, $post_types ),
				'field' => 'post_type.raw',
			),
		);

		return $facet_aggs;
	}

	/**
	 * Add selected filters to the Facet filter in the ES query
	 *
	 * @param array $filters Current Facet filters
	 * @return array
	 */
	public function add_query_filters( $filters ) {
		if ( ! empty( $filters['terms']['post_type.raw'] ) ) {
			return $filters;
		}

		$feature = Features::factory()->get_registered_feature( 'facets' );

		$post_types = $this->get_facetable_post_types();

		if ( empty( $post_types ) ) {
			return $filters;
		}

		$selected_filters = $feature->get_selected();
		if ( empty( $selected_filters ) || empty( $selected_filters[ $this->get_filter_type() ] ) ) {
			return $filters;
		}

		/**
		 * As there is no content with two post types,
		 * if we have a list of types we want *any* content that matches *any* type.
		 */
		$filters[] = [
			'terms' => [
				'post_type.raw' => array_keys( $selected_filters[ $this->get_filter_type() ]['terms'] ),
			],
		];

		return $filters;
	}

	/**
	 * Get the post types that are facetable.
	 *
	 * @return array Array of post types.
	 */
	public function get_facetable_post_types() {
		$searchable_post_types = \ElasticPress\Features::factory()->get_registered_feature( 'search' )->get_searchable_post_types();

		/**
		 * Filter post types that are facetable.
		 *
		 * @since 4.6.0
		 * @hook ep_facetable_post_types
		 * @param {array} $searchable_post_types Array of searchable post types.
		 * @return {array} The array of facetable post types.
		 */
		return apply_filters( 'ep_facetable_post_types', $searchable_post_types );
	}

	/**
	 * Format selected values.
	 *
	 * @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() ] = [
			'terms' => array_fill_keys( array_map( $this->get_sanitize_callback(), $terms ), true ),
		];

		return $filters;
	}

	/**
	 * Add selected filters to the query string.
	 *
	 * @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() ] ?? [];

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

		return $query_params;
	}
}
