<?php
/**
 * The Category discount class
 *
 * @package YITH WooCommerce Dynamic Pricing & Discounts\Classes\Price Rules
 */

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

/**
 * The Category discount Table Class.
 */
class YWDPD_Category_Discount extends YWDPD_Price_Rule {

	/**
	 * Extra data for this object. Name value pairs (name + default value).
	 * Used as a standard way for sub classes (like product types) to add
	 * additional information to an inherited class.
	 *
	 * @since 3.0.0
	 * @var array
	 */
	protected $extra_data = array(
		'quantity_category_discount' => array(),
		'show_in_loop'               => 'yes',
	);


	/**
	 * Get the rule if the ID is passed, otherwise the rule is new and empty.
	 *
	 * @param int|YWDPD_Category_Discount|object $obj ID to load from the DB (optional) or already queried data.
	 *
	 * @throws Exception The exception.
	 */
	public function __construct( $obj = 0 ) {

		parent::__construct( $obj );

		$this->read();
	}

	/**
	 * Set the rule field.
	 *
	 * @param array $rules the rules.
	 *
	 * @since 3.0.0
	 */
	public function set_quantity_category_discount( $rules ) {
		$this->set_prop( 'quantity_category_discount', $rules );
	}

	/**
	 * Set if show the discount on loop.
	 *
	 * @param string $show_in_loop Yes or not.
	 *
	 * @since 3.0.0
	 */
	public function set_show_in_loop( $show_in_loop ) {
		$this->set_prop( 'show_in_loop', $show_in_loop );
	}

	/**
	 * Get if show the discount on loop.
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 * @since 3.0.0
	 */
	public function get_show_in_loop( $context = 'view' ) {
		return $this->get_prop( 'show_in_loop', $context );
	}

	/**
	 * Get the quantity rule fields.
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return array
	 * @since 3.0.0
	 */
	public function get_quantity_category_discount( $context = 'view' ) {
		return $this->get_prop( 'quantity_category_discount', $context );
	}

	/**
	 * Get if the rule is valid for all products or not.
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 * @since 3.0.0
	 */
	public function get_rule_for( $context = 'view' ) {
		return 'specific_categories';
	}

	/**
	 * Check if the discount can show on loop.
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return bool
	 * @since 3.0.0
	 */
	public function can_show_discount_in_loop( $context = 'view' ) {

		$value = yith_plugin_fw_is_true( $this->get_show_in_loop( $context ) );

		if ( 'view' === $context ) {
			/**
			 * APPLY_FILTERS: ywdpd_can_show_discount_in_loop
			 *
			 * Set if show discount in loop.
			 *
			 * @param bool                    $value True or false.
			 * @param YWDPD_Category_Discount $rule  The  rule.
			 *
			 * @return bool
			 */
			$value = apply_filters( 'ywdpd_can_show_discount_in_loop', $value, $this );
		}

		return $value;
	}

	/**
	 * Get the product category ids where apply the rule
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return array
	 * @since 3.0.0
	 */
	public function get_rule_for_categories_list( $context = 'view' ) {
		$rules = $this->get_quantity_category_discount();

		/**
		 * APPLY_FILTERS: ywdpd_price_rule_get_rule_for_categories_list
		 *
		 * Set product category ids.
		 *
		 * @param array                   $product_ids The product ids.
		 * @param YWDPD_Category_Discount $rule        The  rule.
		 *
		 * @return array
		 */
		return apply_filters( 'ywdpd_price_rule_get_rule_for_categories_list', array_unique( wp_list_pluck( $rules, 'product_cat' ) ), $this );
	}

	/**
	 * Check if the rule is valid for apply discount.
	 *
	 * @param WC_Product $product              The product object.
	 * @param bool       $check_also_variation Check also the variation or not.
	 *
	 * @return bool
	 * @since 3.0.0
	 */
	public function is_valid_to_apply( $product, $check_also_variation = false ) {
		$is_valid = false;
		if ( ! $this->is_product_excluded_from_apply( $product ) ) {
			$list_ids = $this->get_rule_for_categories_list();
			$is_valid = $this->is_product_in_list( $product, $list_ids, 'product_cat' );
			/**
			 * APPLY_FILTERS: ywdpd_is_valid_to_apply
			 *
			 * Set if rule is valid.
			 *
			 * @param bool                    $value   True or false.
			 * @param string                  $type    The type.
			 * @param WC_Product              $product the product.
			 * @param YWDPD_Category_Discount $rule    The  rule.
			 *
			 * @return bool
			 */
			$is_valid = apply_filters( 'ywdpd_is_valid_to_apply', $is_valid, 'specific_categories', $product, $this );
		}

		return $is_valid;
	}

	/**
	 * Check if the rule is valid for adjustment discount.
	 *
	 * @param WC_Product $product              The product object.
	 * @param bool       $check_also_variation Check also the variation or not.
	 *
	 * @return bool
	 * @since 3.0.0
	 */
	public function is_valid_to_adjust( $product, $check_also_variation = false ) {
		return false;
	}

	/**
	 * Check if this rule is enabled the adjustment to mode
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return bool
	 * @since 3.0.0
	 */
	public function is_enabled_apply_adjustment_to( $context = 'view' ) {
		return false;
	}

	/**
	 * Return the quantity to check
	 *
	 * @param array $cart_item The cart item.
	 *
	 * @return int;
	 * @since 3.0.0
	 */
	public function get_quantity( $cart_item ) {
		$q = intval( $cart_item['quantity'] );

		return $q;
	}

	/**
	 * Return the new price for the specific quantity
	 *
	 * @param float      $price_to_discount The price to discount.
	 * @param int        $quantity          The quantity.
	 * @param WC_Product $product           The product object.
	 *
	 * @return float
	 * @since 3.0.0
	 */
	public function get_discounted_price( $price_to_discount, $quantity, $product ) {

		if ( $product instanceof WC_Product_Gift_Card ) {
			return $price_to_discount;
		}

		$discounted_price = floatval( $price_to_discount );
		$price_rules      = $this->get_quantity_category_discount();

		if ( $price_to_discount && $quantity >= 1 ) {
			foreach ( $price_rules as $price_rule ) {
				/**
				 * APPLY_FILTERS: ywdpd_single_category_discount
				 *
				 * Set the product category id.
				 *
				 * @param int $category_id The category id.
				 *
				 * @return int
				 */
				$product_cat_id = apply_filters( 'ywdpd_single_category_discount', $price_rule['product_cat'] );

				if ( $this->is_product_in_list( $product, array( $product_cat_id ) ) ) {
					$discount_type   = $price_rule['type_discount'];
					$discount_amount = floatval( str_replace( ',', '.', $price_rule['discount_amount'] ) );

					switch ( $discount_type ) {
						case 'percentage':
							$percent          = $discount_amount / 100;
							$discounted_price = $discounted_price - ( $discounted_price * $percent );
							break;
						case 'price':
							/**
							 * APPLY_FILTERS: ywdpd_maybe_should_be_converted
							 *
							 * Is possible change the discount amount. Useful for multicurrency plugins.
							 *
							 * @param float $discount_amount the discount amount.
							 *
							 * @return float
							 */
							$discount_amount  = apply_filters( 'ywdpd_maybe_should_be_converted', $discount_amount );
							$discounted_price = $discounted_price - $discount_amount;
							break;
						default:
							/**
							 * APPLY_FILTERS: ywdpd_maybe_should_be_converted
							 *
							 * Is possible change the discount amount Useful for multicurrency plugins.
							 *
							 * @param float $discount_amount the discount amount.
							 *
							 * @return float
							 */
							$discounted_price = apply_filters( 'ywdpd_maybe_should_be_converted', $discount_amount );
							break;

					}
					break;
				}
			}
			/**
			 * APPLY_FILTERS: ywdpd_round_total_price
			 *
			 * Allow round totals.
			 *
			 * @param bool $allow_round True or false.
			 *
			 * @return bool
			 */
			if ( apply_filters( 'ywdpd_round_total_price', true ) ) {
				$discounted_price = round( $discounted_price, wc_get_price_decimals() );
			}
		}

		return $discounted_price > 0 ? $discounted_price : 0;
	}

	/**
	 * Get the minimum or the maximum quantity discount rule
	 * For this rule the min and max value is the same and is one.
	 *
	 * @param string $min_or_max Min or max quantity.
	 *
	 * @return int
	 * @author YITH <plugins@yithemes.com>
	 * @since  3.0.0
	 */
	public function get_min_max_quantity_discount_rule( $min_or_max = 'min' ) {
		return 1;
	}

	/**
	 * Add the rule in the cart
	 *
	 * @param string $cart_item_key_to_apply  The item key that allow the apply.
	 * @param string $cart_item_key_to_adjust the cart The item key where add the rule.
	 *
	 * @return bool
	 * @since 3.0.0
	 */
	public function apply_rule_in_cart( $cart_item_key_to_apply, $cart_item_key_to_adjust ) {
		$cart_item_adj = isset( WC()->cart->cart_contents[ $cart_item_key_to_adjust ] ) ? WC()->cart->cart_contents[ $cart_item_key_to_adjust ] : false;
		if ( $cart_item_adj && $this->can_apply_rule( $cart_item_adj ) ) {
			$has_bulk_rule = isset( WC()->cart->cart_contents[ $cart_item_key_to_adjust ]['has_bulk_applied'] );
			if ( ! $has_bulk_rule ) {
				$price_to_discount = $this->get_price_to_discount( $cart_item_adj, $cart_item_key_to_adjust );
				$cart_item_apply   = WC()->cart->cart_contents[ $cart_item_key_to_apply ];
				$quantity          = $this->get_quantity( $cart_item_apply );
				$discounted_price  = $this->get_discounted_price( $price_to_discount, $quantity, $cart_item_adj['data'] );
				$result            = $this->save_discount_in_cart( $cart_item_key_to_adjust, $price_to_discount, $discounted_price );
				if ( $result ) {
					WC()->cart->cart_contents[ $cart_item_key_to_adjust ]['has_bulk_applied'] = true;
				}

				return $result;
			}
		}

		return false;
	}

}

