<?php
/**
 * Bounds filter.
 *
 * @package PRECO
 */

namespace PRECO\Includes\Frontend\Engine\Filters\Price;

defined( 'ABSPATH' ) || exit;

/**
 * Bounds filter.
 */
class BoundsFilter {
	/**
	 * Effective price resolver.
	 *
	 * @var EffectivePriceResolver
	 */
	private $prices;

	/**
	 * Constructor.
	 *
	 * @param EffectivePriceResolver $prices Effective price resolver.
	 */
	public function __construct( EffectivePriceResolver $prices ) {
		$this->prices = $prices;
	}

	/**
	 * Filter product IDs by price bounds using effective WooCommerce price.
	 *
	 * @param int[] $ids Product IDs.
	 * @param array $bounds Bounds.
	 * @return int[]
	 */
	public function filter_ids_by_bounds( $ids, $bounds ) {
		if ( empty( $ids ) || ! is_array( $ids ) ) {
			return array();
		}

		// The driving WP_Query disables post-meta cache priming (see
		// QueryBuilder::build_query_args()) to avoid double-caching, so
		// without this the loop below would issue one uncached get_post_meta
		// round-trip per candidate product (up to 500 on a large candidate
		// pool). Prime it once here instead.
		update_meta_cache( 'post', array_map( 'absint', $ids ) );

		$min           = array_key_exists( 'min', $bounds ) ? $bounds['min'] : null;
		$max           = array_key_exists( 'max', $bounds ) ? $bounds['max'] : null;
		$max_exclusive = ! empty( $bounds['max_exclusive'] );

		$out = array();
		foreach ( $ids as $id ) {
			$pid = absint( $id );
			if ( ! $pid ) {
				continue;
			}

			$price = $this->prices->resolve_for_product_id( $pid );
			if ( null === $price ) {
				continue;
			}

			if ( null !== $min && $price < (float) $min ) {
				continue;
			}
			if ( null !== $max ) {
				if ( $max_exclusive && $price >= (float) $max ) {
					continue;
				}
				if ( ! $max_exclusive && $price > (float) $max ) {
					continue;
				}
			}
			$out[] = $pid;
		}
		return $out;
	}
}
