<?php
/**
 * Gift products class
 *
 * @package YITH WooCommerce Dynamic Pricing & Discounts Premium
 * @since   1.0.0
 * @version 1.6.0
 * @author  YITH <plugins@yithemes.com>
 */

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

if ( ! class_exists( 'YITH_WC_Dynamic_Pricing_Gift_Product' ) ) {

	/**
	 * Class YITH_WC_Dynamic_Pricing_Gift_Product
	 */
	class YITH_WC_Dynamic_Pricing_Gift_Product {
		use YWDPD_Singleton_Trait;


		/**
		 * List of gift rules.
		 *
		 * @var array
		 */
		private $gift_rules = array();

		/**
		 * List of rules to apply.
		 *
		 * @var array
		 */
		private $gift_rules_to_apply = array();

		/**
		 * Constructor
		 */
		private function __construct() {

			add_action( 'init', array( $this, 'load_gift_rules' ), 20 );
			add_action( 'woocommerce_add_to_cart', array( $this, 'check_if_apply_rules' ), 25 );
			add_action( 'woocommerce_after_calculate_totals', array( $this, 'check_if_apply_rules' ), 110 );
			add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'check_if_apply_rules' ), 110 );
			add_action( 'woocommerce_after_calculate_totals', array( $this, 'update_gift_products' ), 20 );
			add_filter( 'woocommerce_update_cart_validation', array( $this, 'check_quantity_security' ), 25, 2 );
			add_filter( 'ywdpd_cart_item_valid_for_count', array( $this, 'exclude_gift_from_quantity' ), 10, 2 );
			add_action( 'woocommerce_checkout_order_processed', 'ywdpd_clear_modal_rule_cookie' );
			add_action( 'wp_footer', array( $this, 'show_popup' ), 25 );
		}

		/**
		 * Load the gift rules
		 */
		public function load_gift_rules() {

			$this->gift_rules = ywdpd_get_price_rules_by_type( 'gift_products' );
		}

		/**
		 * Check if the rule can be applied.
		 */
		public function check_if_apply_rules() {

			if ( ! is_null( WC()->cart ) && ! WC()->cart->is_empty() ) {
				$no_gift_products = $this->get_cart_products();
				$add_rule         = true;
				$cart_has_coupon  = WC()->cart->has_discount();

				if ( count( $no_gift_products ) > 0 ) {
					foreach ( $no_gift_products as $cart_item_key => $cart_item ) {
						foreach ( $this->gift_rules as $rule ) {
							/**
							 * The gift rules
							 *
							 * @var YWDPD_Gift_Products $rule
							 */
							$disabled_with_other_rule     = ! $rule->is_possible_apply_other_rules();
							$items_in_cart                = $rule->get_total_gift_product_in_cart();
							$allowed_item                 = $rule->get_amount_gift_product_allowed();
							$is_enabled_with_other_coupon = ! ( $cart_has_coupon && $rule->is_disabled_with_other_coupon() );

							if ( $is_enabled_with_other_coupon ) {
								if ( YITH_WC_Dynamic_Exclusion_Manager::get_instance()->exclude_item_from_cart( false, $cart_item ) && $rule->is_valid() && $rule->is_valid_for_cart( $cart_item['data'] ) ) {
									if ( $add_rule ) {
										if ( $rule->can_add_to_cart_automatically() ) {
											if ( ( $allowed_item - $items_in_cart ) > 0 ) {
												$rule->add_to_cart();
											}
										} else {
											$this->gift_rules_to_apply[ $rule->get_id() ] = $rule;
										}
									}

									if ( $disabled_with_other_rule ) {
										$add_rule = false;
									} else {
										$add_rule = true;
									}
								}
							}
						}
					}
				}
			}

		}

		/**
		 * Remove all gift product in the cart
		 */
		public function remove_all_gift_product() {

			foreach ( WC()->cart->cart_contents as $cart_item_key => $cart_item ) {

				$is_gift_product = isset( $cart_item['ywdpd_is_gift_product'] );
				if ( $is_gift_product ) {

					/**
					 * Product.
					 *
					 * @var WC_Product $product
					 */
					$product = $cart_item['data'];
					WC()->cart->remove_cart_item( $cart_item_key );
					/* translators: name of product */
					wc_add_notice( sprintf( __( 'Gift %s removed properly', 'ywdpd' ), $product->get_formatted_name() ) );
				}
			}
		}

		/**
		 * Remove gift product from cart.
		 *
		 * @param integer $rule_id Rule id.
		 */
		public function remove_gift_product( $rule_id ) {

			foreach ( WC()->cart->cart_contents as $cart_item_key => $cart_item ) {

				$is_gift_product = isset( $cart_item['ywdpd_is_gift_product'] );
				$cart_rule_id    = isset( $cart_item['ywdpd_rule_id'] ) ? $cart_item['ywdpd_rule_id'] : false;

				if ( $is_gift_product && $cart_rule_id === $rule_id ) {
					$product = $cart_item['data'];
					WC()->cart->remove_cart_item( $cart_item_key );
					/* translators: name of product */
					wc_add_notice( sprintf( __( 'Gift %s removed properly', 'ywdpd' ), $product->get_formatted_name() ) );
				}
			}
		}


		/**
		 * Get the product on cart that aren't gift.
		 *
		 * @return array
		 */
		public function get_cart_products() {

			$products_in_cart = array();
			foreach ( WC()->cart->cart_contents as $cart_item_key => $cart_item ) {

				$is_gift_product = isset( $cart_item['ywdpd_is_gift_product'] );

				if ( ! $is_gift_product ) {

					$products_in_cart[ $cart_item_key ] = $cart_item;
				}
			}

			return $products_in_cart;
		}


		/**
		 * Get the gift rules.
		 */
		public function get_gift_product_to_add_popup() {
			$gift_rules_valid = array();
			if ( count( $this->gift_rules_to_apply ) > 0 ) {

				foreach ( $this->gift_rules_to_apply as $rule ) {
					/**
					 * The gift rule
					 *
					 * @var YWDPD_Gift_Products $rule
					 */
					$key           = $rule->get_id();
					$items_in_cart = $rule->get_total_gift_product_in_cart();
					$allowed_item  = $rule->get_amount_gift_product_allowed();
					$max_units     = $allowed_item;
					$rule_text     = ywdpd_get_note( $rule->get_text_in_modal_gift() );
					$rule_text     = ! empty( $rule_text ) ? $rule_text : __( 'You can add {{total_to_add}} product(s) for free!', 'ywdpd' );
					$remain_to_add = $allowed_item - $items_in_cart;
					if ( $remain_to_add > 0 ) {
						$product_to_gift = yith_ywdpd_filter_onstock_products( $rule->get_gift_product_selection() );
						if ( count( $product_to_gift ) > 0 ) {
							$gift_rules_valid[ $key ] = array(
								'text'         => $rule_text,
								'max_units'    => $max_units,
								'allowed_item' => $remain_to_add,
								'items'        => array(
									'type'     => 'product_ids',
									'item_ids' => $product_to_gift,
								),
								'type'         => 'gift_products',
								'mode'         => 'total_product',
							);
						}
					}
				}
			}

			return $gift_rules_valid;
		}

		/**
		 * Get the gift rule by id
		 *
		 * @param string|int $rule_id The rule id.
		 *
		 * @return false|YWDPD_Gift_Products
		 * @since  3.0.0
		 */
		public function get_gift_rule_to_apply_by_id( $rule_id ) {

			return isset( $this->gift_rules_to_apply[ $rule_id ] ) ? $this->gift_rules_to_apply[ $rule_id ] : false;
		}


		/**
		 * Update gift product.
		 */
		public function update_gift_products() {

			remove_action( 'woocommerce_after_calculate_totals', array( $this, 'update_gift_products' ), 20 );
			$rule_removed    = array();
			$cart_has_coupon = WC()->cart->has_discount();
			foreach ( WC()->cart->get_cart_contents() as $cart_item_key => $cart_item ) {

				$rule_id = $cart_item['ywdpd_rule_id'] ?? false;
				$is_gift = $cart_item['ywdpd_is_gift_product'] ?? false;
				if ( $is_gift ) {
					if ( $rule_id && ! in_array( $rule_id, $rule_removed ) ) { //phpcs:ignore

						$rule = $this->gift_rules_to_apply[ $rule_id ] ?? false;
						if ( ! $rule ) {
							$rule_to_check                = ywdpd_get_rule( $rule_id );
							$is_enabled_with_other_coupon = ! ( $cart_has_coupon && $rule_to_check->is_disabled_with_other_coupon() );
							if ( $rule_to_check && 'gift_products' === $rule_to_check->get_discount_mode() && $rule_to_check->can_add_to_cart_automatically() && $is_enabled_with_other_coupon ) {
								$rule = $rule_to_check;
							}
						}

						if ( ! $rule || ! $this->check_valid_single_rule( $rule ) ) {
							$rule_removed[] = $rule_id;
							$this->remove_gift_product( $rule_id );
						}
					}
				}
			}
			add_action( 'woocommerce_after_calculate_totals', array( $this, 'update_gift_products' ), 20 );
		}


		/**
		 * Check if a rule is valid
		 *
		 * @param YWDPD_Gift_Products $rule Rule.
		 *
		 * @return bool
		 * @since  1.6.0
		 */
		public function check_valid_single_rule( $rule ) {

			$products_in_cart = $this->get_cart_products();

			foreach ( $products_in_cart as $cart_item_key => $cart_item ) {

				if ( $rule->is_valid_for_cart( $cart_item['data'] ) ) {
					return true;
				}
			}

			return false;
		}

		/**
		 * Avoid the change quantity for gift product
		 *
		 * @param string $new_qty The new quantity.
		 * @param string $cart_item_key The cart item key.
		 *
		 * @return string
		 * @since  3.3.4
		 */
		public function check_quantity_security( $new_qty, $cart_item_key ) {

			$cart_item = WC()->cart->cart_contents[ $cart_item_key ];
			$rule_id   = isset( $cart_item['ywdpd_rule_id'] ) ? $cart_item['ywdpd_rule_id'] : false;

			if ( $rule_id ) {
				$new_qty = '';
			}

			return $new_qty;

		}

		/**
		 * Check if can show popup in the page
		 *
		 * @auhtor YITH
		 * @since  2.1
		 */
		public function show_popup() {
			/**
			 * APPLY_FILTERS: ywdpd_can_show_popup.
			 *
			 * Change the page where show the gift popup
			 *
			 * @param bool $show Is true if the current page is the cart page.
			 *
			 * @return bool
			 */
			if ( apply_filters( 'ywdpd_can_show_popup', is_cart() ) ) {
				$this->print_popup_for_gift_rules();
			}

		}

		/**
		 * Show the gift rules in cart
		 *
		 * @since  2.1
		 */
		public function print_popup_for_gift_rules() {
			$items_to_show = $this->get_gift_product_to_add_popup();

			if ( count( $items_to_show ) > 0 ) {
				foreach ( $items_to_show as $rule_id => $item_to_show ) {
					wc_get_template(
						'yith_ywdpd_popup.php',
						array(
							'rule_id'      => $rule_id,
							'item_to_show' => $item_to_show,
							'popup_class'  => 'cart',
						),
						YITH_YWDPD_TEMPLATE_PATH,
						YITH_YWDPD_TEMPLATE_PATH
					);
				}
			}
		}

		/**
		 * Remove gift product for the calculation
		 *
		 * @param bool  $is_valid Is valid for count.
		 * @param array $cart_item The cart item.
		 *
		 * @return bool
		 * @since  3.11.0
		 */
		public function exclude_gift_from_quantity( $is_valid, $cart_item ) {

			if ( isset( $cart_item['ywdpd_is_gift_product'] ) ) {
				if ( isset( $cart_item['ywdpd_rule_id'] ) ) {

					$is_valid = false;
				}
			}

			return $is_valid;
		}
	}

}

/**
 * Unique access to instance of YITH_WC_Dynamic_Pricing_Gift_Product class
 *
 * @return YITH_WC_Dynamic_Pricing_Gift_Product
 */
function YITH_WC_Dynamic_Pricing_Gift_Product() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName
	return YITH_WC_Dynamic_Pricing_Gift_Product::get_instance();
}


