<?php
/**
 * Discounter type 3 model.
 * Percentage Discount.
 *
 * @package flo-sync
 *
 * @phpcs:disable Squiz.Commenting.FunctionComment.MissingParamTag
 */

namespace NMFS\Sync\Items\Campaigns\Models;

use Automattic\WooCommerce\Utilities\NumberUtil;
use WC_Coupon;

defined( 'ABSPATH' ) || exit;

/**
 * Class Discounter_Type_3_Model
 */
class Discounter_Type_3_Model implements Discounter_Interface {


	/**
	 * WooCommerce coupon for this discount
	 *
	 * @var WC_Coupon
	 */
	protected WC_Coupon $coupon;

	/**
	 * All skus valid for this discount
	 *
	 * @var string[]
	 */
	protected array $skus;

	/**
	 * SKU values
	 *
	 * @var object
	 */
	protected object $values;

	/**
	 * Priority
	 *
	 * @var int
	 */
	protected int $priority;

	/**
	 * Cart sum needed to activate this discount
	 *
	 * @var int
	 */
	protected int $threshold_total;

	/**
	 * Discounter_Type_3_Model constructor.
	 *
	 * @param WC_Coupon $coupon          WooCommerce coupon for this discount.
	 * @param string[]  $skus            All skus valid for this discount.
	 * @param object    $values          SKU values.
	 * @param int       $priority        Priority.
	 * @param int       $threshold_total Cart sum needed to activate this discount.
	 */
	public function __construct( WC_Coupon $coupon, array $skus, object $values, int $priority, int $threshold_total ) {
		$this->coupon          = $coupon;
		$this->skus            = $skus;
		$this->values          = $values;
		$this->priority        = $priority;
		$this->threshold_total = $threshold_total;
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_name(): string {
		return __( 'Percent Discount', 'flo-sync' );
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_coupon(): WC_Coupon {
		return $this->coupon;
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_priority(): int {
		return $this->priority;
	}

	/**
	 * {@inheritDoc}
	 */
	public function is_applicable( float $cart_total, array $products ): bool {
		if ( $cart_total < $this->threshold_total ) {
			return false;
		}

		$applicable_products = $this->applicable_products( $products );

		if ( count( $applicable_products ) < 1 ) {
			return false;
		}

		foreach ( $applicable_products as $applicable_product ) {
			$applicable_product->add_use();
		}

		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_discounted_products( array $products, float $cart_total ): array {
		return $this->inner_get_discounted_products(
			$this->applicable_products( $products ),
			$cart_total
		);
	}

	/**
	 * Get applicable products.
	 *
	 * @param Product_Model[] $products Products to get discount for.
	 *
	 * @return array
	 */
	protected function applicable_products( array $products ): array {
		$skus = $this->skus;

		return array_filter(
			$products,
			function ( $product ) use ( $skus ) {
				if ( $product->get_uses() > 0 ) {
					return false;
				}

				return in_array( $product->get_sku(), $skus, true );
			}
		);
	}

	/**
	 * Get discounted products.
	 *
	 * @param Product_Model[] $products                 Products to get discount for.
	 * @param float           $maximum_allowed_discount Maximum allowed discount.
	 *
	 * @return Product_Model[]
	 */
	protected function inner_get_discounted_products( array $products, float $maximum_allowed_discount ): array {
		if ( empty( $products ) ) {
			return array();
		}

		foreach ( $products as $product ) {
			$discount = NumberUtil::round(
				$product->get_price() * ( $this->get_value_of_sku( $product->get_sku() ) / 100 ),
				wc_get_rounding_precision()
			);

			if ( $maximum_allowed_discount >= $discount ) {
				$product->set_discount( $discount );
				$maximum_allowed_discount -= $discount;
			}
		}

		return $products;
	}

	/**
	 * Gets value of sku from values array
	 *
	 * @param string $sku SKU to get value for.
	 *
	 * @return float
	 */
	protected function get_value_of_sku( string $sku ): float {
		if ( property_exists( $this->values, $sku ) ) {
			return floatval( $this->values->{$sku} );
		}

		return 0.0;
	}
}
