<?php
/**
 * Display Discounted Price with Original and Coupon Percentage
 *
 * @author      StoreApps
 * @since       3.3.0
 * @version     1.0.0
 *
 * @package     woocommerce-smart-coupons/includes/
 */

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

if ( ! class_exists( 'WC_SC_Display_Discounted_Price' ) ) {

	/**
	 * Class for displaying original price, discounted price, and coupon percentage in cart
	 */
	class WC_SC_Display_Discounted_Price {

		/**
		 * Instance of the class
		 *
		 * @var WC_SC_Display_Discounted_Price
		 */
		private static $instance = null;

		/**
		 * Discounted Products
		 *
		 * @var $discounted_products
		 */
		public $discounted_products = array();

		/**
		 * Constructor.
		 */
		private function __construct() {
			$wc_sc_display_discount = get_option( 'wc_sc_display_discount', array() );

			if ( isset( $wc_sc_display_discount['show_crossed_discounted_price'] ) && 'yes' === $wc_sc_display_discount['show_crossed_discounted_price'] ) {
				add_filter( 'woocommerce_cart_item_subtotal', array( $this, 'display_discounted_price' ), 10, 3 );
			}
		}

		/**
		 * Get single instance of WC_SC_Display_Discounted_Price
		 *
		 * @return WC_SC_Display_Discounted_Price Singleton instance
		 */
		public static function get_instance() {
			if ( is_null( self::$instance ) ) {
				self::$instance = new self();
			}

			return self::$instance;
		}

		/**
		 * Handle call to functions which is not available in this class
		 *
		 * @param string $function_name The function name.
		 * @param array  $arguments Array of arguments passed while calling $function_name.
		 * @return result of function call
		 */
		public function __call( $function_name, $arguments = array() ) {

			global $woocommerce_smart_coupon;

			if ( ! is_callable( array( $woocommerce_smart_coupon, $function_name ) ) ) {
				return;
			}

			if ( ! empty( $arguments ) ) {
				return call_user_func_array( array( $woocommerce_smart_coupon, $function_name ), $arguments );
			} else {
				return call_user_func( array( $woocommerce_smart_coupon, $function_name ) );
			}
		}

		/**
		 * Display original price, discounted price, and coupon percentage.
		 *
		 * @param string $product_price The HTML price.
		 * @param array  $cart_item     The cart item data.
		 * @param string $cart_item_key The cart item key.
		 * @return string
		 */
		public function display_discounted_price( $product_price = '', $cart_item = array(), $cart_item_key = '' ) {
			try {
				if ( ! is_array( $cart_item ) || empty( $cart_item['data'] ) || ! $cart_item['data'] instanceof WC_Product ) {
					return $product_price;
				}

				$cart = WC()->cart;
				if ( ! is_object( $cart ) || empty( $cart->get_applied_coupons() ) ) {
					return $product_price;
				}

				$item_subtotal = $cart_item['line_subtotal'] ?? 0;
				$item_total    = isset( $cart_item['line_total'] ) && $cart_item['line_total'] > 0 ? $cart_item['line_total'] : $item_subtotal;

				$discount_for_item      = 0;
				$coupon_discount_totals = $cart->get_coupon_discount_totals();

				if ( is_array( $coupon_discount_totals ) && ! empty( $coupon_discount_totals ) ) {
					foreach ( $coupon_discount_totals as $coupon_code => $coupon_total ) {
						$coupon = new WC_Coupon( $coupon_code );

						if ( $this->is_valid( $coupon ) && $coupon->is_type( 'smart_coupon' ) ) {

							if ( $this->is_wc_gte_30() ) {
								$coupon_code               = $coupon->get_code();
								$coupon_product_ids        = $coupon->get_product_ids();
								$coupon_product_categories = $coupon->get_product_categories();
							} else {
								$coupon_code               = ( ! empty( $coupon->code ) ) ? $coupon->code : '';
								$coupon_product_ids        = ( ! empty( $coupon->product_ids ) ) ? $coupon->product_ids : array();
								$coupon_product_categories = ( ! empty( $coupon->product_categories ) ) ? $coupon->product_categories : array();
							}

							$coupon_amount = $this->get_amount( $coupon, true );

							$coupon_product_ids           = $coupon->get_product_ids();
							$coupon_category_ids          = $coupon->get_product_categories();
							$coupon_taxonomy_restrictions = ( $this->is_callable( $coupon, 'get_meta' ) ) ? $coupon->get_meta( 'wc_sc_taxonomy_restrictions' ) : $this->get_post_meta( $coupon->get_id(), 'wc_sc_taxonomy_restrictions', true );
							$coupon_attribute_ids         = ( $this->is_callable( $coupon, 'get_meta' ) ) ? $coupon->get_meta( 'wc_sc_product_attribute_ids' ) : $this->get_post_meta( $coupon->get_id(), 'wc_sc_product_attribute_ids', true );
							$brand_coupon_settings        = $this->get_coupon_brand_settings( $coupon->get_id() );

							if ( ! empty( $coupon_product_ids ) || ! empty( $coupon_category_ids ) || ! empty( $coupon_attribute_ids ) || ! empty( $coupon_taxonomy_restrictions ) ||
								(
									is_array( $brand_coupon_settings ) &&
									( ! empty( $brand_coupon_settings['included_brands'] ) || ! empty( $brand_coupon_settings['excluded_brands'] ) )
								)
							) {

								// Woocommerce validate cart item is vaild for coupon.
								$valid = $coupon->is_valid_for_product( $cart_item['data'], $cart_item ) ? true : false;

								if ( ! $valid ) {
									continue;
								}

								$continue = false;

								if ( ! empty( $cart_item_key ) && ! empty( $discounted_products ) && is_array( $discounted_products ) && in_array( $cart_item_key, $discounted_products, true ) ) {
									$continue = true;
								}

								/**
								 * Filter to allow us to validate store credit if applicable to any line item.
								 *
								 * @param WC_Product|null $cart_item['data'] Product object.
								 * @param WC_Coupon|null  $coupon Coupon object.
								 * @param array|null      $cart_item Cart Item.
								 * @since 9.33.0
								 */
								$valid = apply_filters(
									'is_sc_valid_apply_credit',
									$valid,
									$cart_item['data'],
									$coupon,
									$cart_item
								);

								if ( ! $continue && $valid ) {

									$item_total = $cart_item['line_total'] + $cart_item['line_tax'];
									$item_total = ( isset( $this->discounted_products[ $cart_item_key ] ) ) ? min( $this->discounted_products[ $cart_item_key ], $item_total ) : $item_total;

									$discount                                    = min( $coupon_amount, $item_total );
									$coupon_amount                               = $coupon_amount - $discount;
									$this->discounted_products[ $cart_item_key ] = $item_total - $discount;
									$discount_for_item                          += $discount;

								}

								$cart_subtotal                   = $this->is_callable( WC()->cart, 'get_subtotal' ) ? (float) WC()->cart->get_subtotal() : 0;
								$cart_subtotal_tax               = $this->is_callable( WC()->cart, 'get_subtotal_tax' ) ? (float) WC()->cart->get_subtotal_tax() : 0;
								$discount_by_wc                  = WC()->cart->get_discount_total() + WC()->cart->get_discount_tax();
								$remaining_amount_should_include = (float) WC()->cart->get_total( 'context' ) + $discount_by_wc - ( $cart_subtotal + $cart_subtotal_tax ) - array_sum( $this->discounted_cart_extra );

								if ( $remaining_amount_should_include > 0 && $coupon_amount > 0 ) {

									$extra_discount                              = min( $remaining_amount_should_include, $coupon_amount );
									$discount_for_item                          += $extra_discount;
									$coupon_amount                              -= $extra_discount;
									$this->discounted_cart_extra[ $coupon_code ] = $extra_discount;
								}
							} else {
								$discount_for_item = min( $item_total, $coupon_amount );
							}
						} else {
							$discount_for_item = $item_subtotal - $item_total;
						}
					}
				}

				$quantity              = max( 1, $cart_item['quantity'] ?? 1 );
				$item_price            = $item_subtotal;
				$item_price_discounted = max( 0, $item_price - $discount_for_item );

				// Calculate discount percent.
				$discount_percent = round( ( ( $item_price - $item_price_discounted ) / max( 0.01, $item_price ) ) * 100 );

				if ( $discount_percent > 0 ) {
					$product_price  = '<del>' . wc_price( $item_price ) . '</del> ';
					$product_price .= '<ins>' . wc_price( $item_price_discounted ) . '</ins>';
					$product_price .= '<br><small class="wc-coupon-discount"><em>'
									/* translators: %d: discount percentage applied by the coupon */
									. sprintf( __( '*Coupon discount %d%%', 'woocommerce' ), $discount_percent )
									. '</em></small>';
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $product_price;
		}
	}
}

WC_SC_Display_Discounted_Price::get_instance();
