<?php
/**
 * Compatibility file for WooCommerce Subscriptions
 *
 * @author      StoreApps
 * @since       3.3.0
 * @version     2.10.0
 * @package     WooCommerce Smart Coupons
 */

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

if ( ! class_exists( 'WCS_SC_Compatibility' ) ) {

	/**
	 * Class for handling compatibility with WooCommerce Subscriptions
	 */
	class WCS_SC_Compatibility {

		/**
		 * Variable to hold instance of WCS_SC_Compatibility
		 *
		 * @var $instance
		 */
		private static $instance = null;

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

			if ( ! function_exists( 'is_plugin_active' ) ) {
				require_once ABSPATH . 'wp-admin/includes/plugin.php';
			}

			if ( is_plugin_active( 'woocommerce-subscriptions/woocommerce-subscriptions.php' ) ) {
				add_action( 'wp_loaded', array( $this, 'sc_wcs_renewal_filters' ), 20 );
				add_filter( 'wc_sc_sections_with_settings', array( $this, 'smart_coupons_settings' ) );
				add_filter( 'wcs_bypass_coupon_removal', array( $this, 'bypass_removal_of_coupon_having_coupon_actions' ), 10, 4 );
				add_filter( 'woocommerce_subscriptions_calculated_total', array( $this, 'modify_recurring_cart' ) );
				add_action( 'wp_loaded', array( $this, 'hooks_for_wcs_230' ) );
				add_filter( 'wc_sc_endpoint_account_settings_after_key', array( $this, 'endpoint_account_settings_after_key' ), 10, 2 );
				add_filter( 'wc_sc_coupon_type', array( $this, 'valid_display_type' ), 11, 3 );
				add_filter( 'wc_sc_coupon_amount', array( $this, 'valid_display_amount' ), 11, 2 );
				add_filter( 'wc_sc_coupon_design_thumbnail_src_set', array( $this, 'coupon_design_thumbnail_src_set' ), 10, 2 );
				add_filter( 'wc_sc_percent_discount_types', array( $this, 'percent_discount_types' ), 10, 2 );
				add_filter( 'wc_sc_is_auto_apply', array( $this, 'is_auto_apply' ), 10, 2 );
				add_action( 'wcs_before_parent_order_setup_cart', array( $this, 'maybe_revalidate_coupon_actions' ), 999, 2 );
				add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles_scripts' ), 20 );
				add_action( 'wc_sc_add_option', array( $this, 'add_option' ) );
				add_filter( 'wc_sc_system_status_items', array( $this, 'system_status_items' ), 10, 2 );
				add_filter( 'wc_sc_is_auto_generate', array( $this, 'disable_auto_generate_coupon_for_switch_subscription_item' ), 10, 2 );

			}

		}

		/**
		 * Get single instance of WCS_SC_Compatibility
		 *
		 * @return WCS_SC_Compatibility Singleton object of WCS_SC_Compatibility
		 */
		public static function get_instance() {
			// Check if instance is already exists.
			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 Function to call.
		 * @param array  $arguments Array of arguments passed while calling $function_name.
		 * @return mixed 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 ) );
			}
		}

		/**
		 * Function to manage appropriate filter for applying Smart Coupons feature in renewal order
		 */
		public function sc_wcs_renewal_filters() {
			if ( self::is_wcs_gte( '2.0.0' ) ) {
				if ( self::is_wcs_gte( '2.5.0' ) ) {
					add_filter( 'wc_subscriptions_renewal_order_data', array( $this, 'sc_wcs_renewal_order_meta' ), 10, 3 );
				} else {
					add_filter( 'wcs_renewal_order_meta', array( $this, 'sc_wcs_renewal_order_meta' ), 10, 3 );
				}
				add_filter( 'wcs_get_subscription', array( $this, 'sc_wcs_modify_subscription' ) );
				add_filter( 'wcs_new_order_created', array( $this, 'sc_wcs_modify_renewal_order_meta' ), 10, 2 );
				add_filter( 'wcs_renewal_order_items', array( $this, 'sc_wcs_modify_renewal_order' ), 10, 3 );
				add_filter( 'wcs_renewal_order_items', array( $this, 'sc_wcs_renewal_order_items' ), 10, 3 );
				add_filter( 'wcs_renewal_order_created', array( $this, 'sc_wcs_renewal_complete_payment' ), 10, 2 );
				add_action( 'woocommerce_update_order', array( $this, 'smart_coupons_contribution' ), 8 );
				add_filter( 'is_show_gift_certificate_receiver_detail_form', array( $this, 'is_show_gift_certificate_receiver_detail_form' ), 10, 2 );
				if ( self::is_wcs_gte( '5.7.0' ) ) {
					add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'modify_store_api_renewal_order' ) );
				}
			} else {
				add_filter( 'woocommerce_subscriptions_renewal_order_items', array( $this, 'sc_modify_renewal_order' ), 10, 5 );
				add_filter( 'woocommerce_subscriptions_renewal_order_items', array( $this, 'sc_subscriptions_renewal_order_items' ), 10, 5 );
				add_action( 'woocommerce_subscriptions_renewal_order_created', array( $this, 'sc_renewal_complete_payment' ), 10, 4 );
			}
		}

		/**
		 * Function to manage payment method for renewal orders based on availability of store credit (WCS 2.0+)
		 *
		 * @param WC_Subscription $subscription Subscription object.
		 * @return WC_Subscription $subscription
		 */
		public function sc_wcs_modify_subscription( $subscription = null ) {
			try {
				if ( did_action( 'woocommerce_scheduled_subscription_payment' ) < 1 ) {
					return $subscription;
				}

				if ( ! empty( $subscription ) && $subscription instanceof WC_Subscription ) {

					$pay_from_credit_of_original_order = get_option( 'pay_from_smart_coupon_of_original_order', 'yes' );

					if ( 'yes' !== $pay_from_credit_of_original_order ) {
						return $subscription;
					}

					if ( $this->is_wc_gte_30() ) {
						$subscription_parent_order = $subscription->get_parent();
						$original_order_id         = ( is_object( $subscription_parent_order ) && is_callable( array( $subscription_parent_order, 'get_id' ) ) ) ? $subscription_parent_order->get_id() : 0;
					} else {
						$original_order_id = ( ! empty( $subscription->order->id ) ) ? $subscription->order->id : 0;
					}

					if ( empty( $original_order_id ) ) {
						return $subscription;
					}

					$renewal_total                 = $subscription->get_total();
					$original_order                = wc_get_order( $original_order_id );
					$coupon_used_in_original_order = $this->get_coupon_codes( $original_order );

					if ( $this->is_wc_gte_30() ) {
						$order_payment_method = $original_order->get_payment_method();
					} else {
						$order_payment_method = ( ! empty( $original_order->payment_method ) ) ? $original_order->payment_method : 0;
					}

					if ( count( $coupon_used_in_original_order ) > 0 ) {
						foreach ( $coupon_used_in_original_order as $coupon_code ) {
							$coupon = new WC_Coupon( $coupon_code );
							if ( $this->is_wc_gte_30() ) {
								$discount_type = $coupon->get_discount_type();
							} else {
								$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
							}
							$coupon_amount = $this->get_amount( $coupon, true, $original_order );
							if ( ! empty( $discount_type ) && 'smart_coupon' === $discount_type && ! empty( $coupon_amount ) ) {
								if ( $coupon_amount >= $renewal_total ) {
									$subscription->set_payment_method( '' );
								} else {
									$payment_gateways = WC()->payment_gateways->get_available_payment_gateways();
									if ( ! empty( $payment_gateways[ $order_payment_method ] ) ) {
										$payment_method = $payment_gateways[ $order_payment_method ];
										$subscription->set_payment_method( $payment_method );
									}
								}
							}
						}
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $subscription;
		}

		/**
		 * Function to add meta which is necessary for coupon processing, in order
		 *
		 * @param   array    $meta Order meta.
		 * @param   WC_Order $to_order Order to copy meta to.
		 * @param   WC_Order $from_order Order to copy meta from.
		 * @return  array $meta
		 */
		public function sc_wcs_renewal_order_meta( $meta = array(), $to_order = null, $from_order = null ) {
			try {
				if ( $this->is_wc_gte_30() ) {
					$order    = $from_order->get_parent();
					$order_id = ( is_object( $order ) && is_callable( array( $order, 'get_id' ) ) ) ? $order->get_id() : 0;
				} else {
					$order    = $from_order->order;
					$order_id = ( ! empty( $order->id ) ) ? $order->id : 0;
				}

				if ( empty( $order_id ) ) {
					return $meta;
				}

				$is_callable_order_get_meta = $this->is_callable( $order, 'get_meta' );

				$meta_exists = array(
					'coupon_sent'                => false,
					'gift_receiver_email'        => false,
					'gift_receiver_message'      => false,
					'sc_called_credit_details'   => false,
					'smart_coupons_contribution' => false,
				);

				foreach ( $meta as $index => $data ) {
					if ( $this->is_wcs_gte( '2.2.0' ) ) {
						if ( is_object( $data ) ) {
							$data = (array) $data;
						}
						$meta_key = '';
						if ( $this->is_wcs_gte( '4.7.0' ) ) {
							$meta_key = $index;
						} elseif ( is_array( $data ) && ! empty( $data['meta_key'] ) ) {
							$meta_key = $data['meta_key'];
						}

						if ( ! empty( $meta_key ) ) {
							$unprefixed_key = ( wcs_maybe_prefix_key( $meta_key ) === $meta_key ) ? substr( $meta_key, 1 ) : $meta_key;
							if ( array_key_exists( $unprefixed_key, $meta_exists ) ) {
								unset( $meta[ $meta_key ] );
							}
						}
					} else {
						if ( ! empty( $data['meta_key'] ) && array_key_exists( $data['meta_key'], $meta_exists ) ) {
							$meta_exists[ $data['meta_key'] ] = true; // phpcs:ignore
						}
					}
				}

				foreach ( $meta_exists as $key => $value ) {
					if ( $value ) {
						continue;
					}
					$meta_value = ( true === $is_callable_order_get_meta ) ? $order->get_meta( $key ) : get_post_meta( $order_id, $key, true );

					if ( empty( $meta_value ) ) {
						continue;
					}

					if ( $this->is_wcs_gte( '2.2.0' ) ) {
						$renewal_order_id                 = ( $this->is_callable( $to_order, 'get_id' ) ) ? $to_order->get_id() : 0;
						$is_callable_to_order_update_meta = $this->is_callable( $to_order, 'update_meta_data' );
						if ( 'coupon_sent' === $key ) {
							// No need to update meta 'coupon_sent' as it's being updated by function sc_modify_renewal_order in this class.
							continue;
						} elseif ( 'smart_coupons_contribution' === $key ) {
							if ( true === $is_callable_to_order_update_meta ) {
								$to_order->update_meta_data( $key, array() );
							} else {
								update_post_meta( $renewal_order_id, $key, array() );
							}
						} else {
							if ( true === $is_callable_to_order_update_meta ) {
								$to_order->update_meta_data( $key, $meta_value );
							} else {
								update_post_meta( $renewal_order_id, $key, $meta_value );
							}
						}
					} else {
						if ( ! isset( $meta ) || ! is_array( $meta ) ) {
							$meta = array();
						}
						$meta[] = array(
							'meta_key'   => $key, // phpcs:ignore
							'meta_value' => $meta_value, // phpcs:ignore
						);
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $meta;
		}

		/**
		 * Function to modify renewal order meta
		 *
		 * @param WC_Order        $renewal_order Order created on subscription renewal.
		 * @param WC_Subscription $subscription Subscription we're basing the order off of.
		 * @return WC_Order $renewal_order
		 */
		public function sc_wcs_modify_renewal_order_meta( $renewal_order = null, $subscription = null ) {
			try {
				global $wpdb;

				if ( $this->is_wc_gte_30() ) {
					$renewal_order_id = ( is_object( $renewal_order ) && is_callable( array( $renewal_order, 'get_id' ) ) ) ? $renewal_order->get_id() : 0;
				} else {
					$renewal_order_id = ( ! empty( $renewal_order->id ) ) ? $renewal_order->id : 0;
				}

				if ( empty( $renewal_order_id ) ) {
					return $renewal_order;
				}

				$sc_called_credit_details = $this->get_post_meta( $renewal_order_id, 'sc_called_credit_details', true, true, $renewal_order );
				if ( empty( $sc_called_credit_details ) ) {
					return $renewal_order;
				}

				$old_order_item_ids = ( ! empty( $sc_called_credit_details ) ) ? array_keys( $sc_called_credit_details ) : array();

				if ( ! empty( $old_order_item_ids ) ) {

					$old_order_item_ids = array_map( 'absint', $old_order_item_ids );

					$meta_keys   = array( '_variation_id', '_product_id' );
					$how_many    = count( $old_order_item_ids );
					$placeholder = array_fill( 0, $how_many, '%d' );

					$meta_keys = esc_sql( $meta_keys );

					// @codingStandardsIgnoreStart.
					$query_to_fetch_product_ids = $wpdb->prepare(
						"SELECT woim.order_item_id,
						(CASE
							WHEN woim.meta_key = %s AND woim.meta_value > 0 THEN woim.meta_value
							WHEN woim.meta_key = %s AND woim.meta_value > 0 THEN woim.meta_value
						END) AS product_id
						FROM {$wpdb->prefix}woocommerce_order_itemmeta AS woim
						WHERE woim.order_item_id IN ( " . implode( ',', $placeholder ) . " )
							AND woim.meta_key IN ( %s, %s )
						GROUP BY woim.order_item_id",
						array_merge( $meta_keys, $old_order_item_ids, array_reverse( $meta_keys ) )
					);
					// @codingStandardsIgnoreEnd.

					$product_ids_results = $wpdb->get_results( $query_to_fetch_product_ids, ARRAY_A ); // phpcs:ignore

					if ( ! is_wp_error( $product_ids_results ) && ! empty( $product_ids_results ) ) {
						$product_to_old_item = array();
						foreach ( $product_ids_results as $result ) {
							$product_to_old_item[ $result['product_id'] ] = $result['order_item_id'];
						}

						$found_product_ids = ( ! empty( $product_to_old_item ) ) ? $product_to_old_item : array();

						$query_to_fetch_new_order_item_ids = $wpdb->prepare(
							"SELECT woim.order_item_id,
																				(CASE
																					WHEN woim.meta_value > 0 THEN woim.meta_value
																				END) AS product_id
																				FROM {$wpdb->prefix}woocommerce_order_items AS woi
																					LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS woim
																						ON (woim.order_item_id = woi.order_item_id AND woim.meta_key IN ( %s, %s ))
																				WHERE woi.order_id = %d
																					AND woim.order_item_id IS NOT NULL
																				GROUP BY woim.order_item_id",
							'_product_id',
							'_variation_id',
							$renewal_order_id
						);

						$new_order_item_ids_result = $wpdb->get_results( $query_to_fetch_new_order_item_ids, ARRAY_A ); // phpcs:ignore

						if ( ! is_wp_error( $new_order_item_ids_result ) && ! empty( $new_order_item_ids_result ) ) {
							$product_to_new_item = array();
							foreach ( $new_order_item_ids_result as $result ) {
								$product_to_new_item[ $result['product_id'] ] = $result['order_item_id'];
							}
						}
					}
				}
				foreach ( $sc_called_credit_details as $item_id => $credit_amount ) {
					$product_id = array_search( $item_id, $product_to_old_item, true );
					if ( false !== $product_id ) {
						$sc_called_credit_details[ $product_to_new_item[ $product_id ] ] = $credit_amount;
						unset( $sc_called_credit_details[ $product_to_old_item[ $product_id ] ] );
					}
				}

				$this->update_post_meta( $renewal_order_id, 'sc_called_credit_details', $sc_called_credit_details, true, $renewal_order );
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
			return $renewal_order;
		}

		/**
		 * New function to handle auto generation of coupon from renewal orders (WCS 2.0+)
		 *
		 * @param array           $order_items Order items.
		 * @param WC_Order        $renewal_order Order created on subscription renewal.
		 * @param WC_Subscription $subscription Subscription we're basing the order off of.
		 * @return array $order_items
		 */
		public function sc_wcs_modify_renewal_order( $order_items = null, $renewal_order = null, $subscription = null ) {
			try {
				if ( $this->is_wc_gte_30() ) {
					$subscription_parent_order = $subscription->get_parent();
					$subscription_order_id     = ( is_object( $subscription_parent_order ) && is_callable( array( $subscription_parent_order, 'get_id' ) ) ) ? $subscription_parent_order->get_id() : 0;
					$renewal_order_id          = ( is_callable( array( $renewal_order, 'get_id' ) ) ) ? $renewal_order->get_id() : 0;
				} else {
					$subscription_order_id = ( ! empty( $subscription->order->id ) ) ? $subscription->order->id : 0;
					$renewal_order_id      = ( ! empty( $renewal_order->id ) ) ? $renewal_order->id : 0;
				}

				$order_items = $this->sc_modify_renewal_order( $order_items, $subscription_order_id, $renewal_order_id );
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
			return $order_items;
		}

		/**
		 * New function to modify order_items of renewal order (WCS 2.0+)
		 *
		 * @param array           $order_items Order items.
		 * @param WC_Order        $renewal_order Order created on subscription renewal.
		 * @param WC_Subscription $subscription Subscription we're basing the order off of.
		 * @return array $order_items
		 */
		public function sc_wcs_renewal_order_items( $order_items = null, $renewal_order = null, $subscription = null ) {
			try {
				if ( $this->is_wc_gte_30() ) {
					$subscription_parent_order = $subscription->get_parent();
					$subscription_order_id     = ( is_object( $subscription_parent_order ) && is_callable( array( $subscription_parent_order, 'get_id' ) ) ) ? $subscription_parent_order->get_id() : 0;
					$renewal_order_id          = ( is_callable( array( $renewal_order, 'get_id' ) ) ) ? $renewal_order->get_id() : 0;
				} else {
					$subscription_order_id = ( ! empty( $subscription->order->id ) ) ? $subscription->order->id : 0;
					$renewal_order_id      = ( ! empty( $renewal_order->id ) ) ? $renewal_order->id : 0;
				}

				$order_items = $this->sc_subscriptions_renewal_order_items( $order_items, $subscription_order_id, $renewal_order_id, 0, 'child' );
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
			return $order_items;
		}

		/**
		 * New function to mark payment complete for renewal order (WCS 2.0+)
		 *
		 * @param WC_Order        $renewal_order Order object.
		 * @param WC_Subscription $subscription Subscription we're basing the order off of.
		 * @return WC_Order $renewal_order
		 */
		public function sc_wcs_renewal_complete_payment( $renewal_order = null, $subscription = null ) {

			$this->sc_renewal_complete_payment( $renewal_order );

			return $renewal_order;
		}

		/**
		 * Function to save Smart Coupon's contribution in discount
		 *
		 * @param int $order_id Order ID.
		 */
		public function smart_coupons_contribution( $order_id = 0 ) {
			try {
				if ( did_action( 'woocommerce_update_order' ) > 1 ) {
					return;
				}

				if ( self::is_wcs_gte( '2.0.0' ) ) {
					$is_renewal_order = wcs_order_contains_renewal( $order_id );
				} else {
					$is_renewal_order = WC_Subscriptions_Renewal_Order::is_renewal( $order_id );
				}

				if ( ! $is_renewal_order ) {
					return;
				}

				$applied_coupons = ( is_object( WC()->cart ) && isset( WC()->cart->applied_coupons ) ) ? WC()->cart->applied_coupons : array();

				if ( ! empty( $applied_coupons ) ) {

					$order_id = absint( $order_id );
					$order    = ( function_exists( 'wc_get_order' ) ) ? wc_get_order( $order_id ) : null;

					foreach ( $applied_coupons as $code ) {

						$smart_coupon = new WC_Coupon( $code );

						if ( $this->is_wc_gte_30() ) {
							$discount_type = $smart_coupon->get_discount_type();
						} else {
							$discount_type = ( ! empty( $smart_coupon->discount_type ) ) ? $smart_coupon->discount_type : '';
						}

						if ( 'smart_coupon' === $discount_type ) {

							$smart_coupon_credit_used = ( $this->is_callable( $order, 'get_meta' ) ) ? $order->get_meta( 'smart_coupons_contribution' ) : $this->get_post_meta( $order_id, 'smart_coupons_contribution', true, true );

							$cart_smart_coupon_credit_used = WC()->cart->smart_coupon_credit_used;

							$update = false;

							if ( ! empty( $smart_coupon_credit_used ) ) {
								if ( ! empty( $cart_smart_coupon_credit_used ) ) {
									foreach ( $cart_smart_coupon_credit_used as $code => $amount ) {
										$smart_coupon_credit_used[ $code ] = $amount;
										$update                            = true;
									}
								}
							} else {
								$smart_coupon_credit_used = $cart_smart_coupon_credit_used;
								$update                   = true;
							}

							if ( $update ) {
								if ( $this->is_callable( $order, 'update_meta_data' ) ) {
									$order->update_meta_data( 'smart_coupons_contribution', $smart_coupon_credit_used );
								} else {
									$this->update_post_meta( $order_id, 'smart_coupons_contribution', $smart_coupon_credit_used, true, $order );
								}
							}
						}
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Get first order of a subscription to which the supplied order belongs
		 *
		 * @param  integer $order_id The order id.
		 * @return integer
		 */
		public function get_first_order_id( $order_id = 0 ) {
			if ( self::is_wcs_gte( '2.0.0' ) && ! empty( $order_id ) ) {
				$subscriptions     = wcs_get_subscriptions_for_order( $order_id );
				$related_order_ids = ( is_object( $subscriptions ) && is_callable( array( $subscriptions, 'get_related_order_ids' ) ) ) ? $subscriptions->get_related_order_ids() : array();
				$related_order_ids = array_filter( $related_order_ids );
				if ( ! empty( $related_order_ids ) ) {
					sort( $related_order_ids, SORT_NUMERIC );
					reset( $related_order_ids );
					return current( $related_order_ids );
				}
			}
			return 0;
		}

		/**
		 * Set 'coupon_sent' as 'no' for renewal order to allow auto generation of coupons (if applicable)
		 *
		 * @param array  $order_items Associative array of order items.
		 * @param int    $original_order_id Post ID of the order being used to purchased the subscription being renewed.
		 * @param int    $renewal_order_id Post ID of the order created for renewing the subscription.
		 * @param int    $product_id ID of the product being renewed.
		 * @param string $new_order_role The role the renewal order is taking, one of 'parent' or 'child'.
		 * @return array $order_items
		 */
		public function sc_modify_renewal_order( $order_items = null, $original_order_id = 0, $renewal_order_id = 0, $product_id = 0, $new_order_role = null ) {
			try {
				if ( empty( $original_order_id ) && empty( $renewal_order_id ) ) {
					return $order_items;
				}

				if ( empty( $original_order_id ) ) {
					$original_order_id = $this->get_first_order_id( $renewal_order_id );
					if ( empty( $original_order_id ) ) {
						return $order_items;
					}
				}

				if ( self::is_wcs_gte( '2.0.0' ) ) {
					$is_subscription_order = wcs_order_contains_subscription( $original_order_id );
				} else {
					$is_subscription_order = WC_Subscriptions_Order::order_contains_subscription( $original_order_id );
				}
				if ( $is_subscription_order ) {
					$return = false;
				} else {
					$return = true;
				}
				if ( $return ) {
					return $order_items;
				}

				$is_recursive = false;
				if ( ! empty( $order_items ) ) {
					foreach ( $order_items as $order_item ) {
						$send_coupons_on_renewals            = 'no';
						$item_product_id                     = ( $this->is_callable( $order_item, 'get_product_id' ) ) ? $order_item->get_product_id() : $order_item['product_id'];
						$item_variation_id                   = ( $this->is_callable( $order_item, 'get_variation_id' ) ) ? $order_item->get_variation_id() : $order_item['variation_id'];
						$item_product                        = ( ! empty( $item_product_id ) && function_exists( 'wc_get_product' ) ) ? wc_get_product( $item_product_id ) : null;
						$item_variation                      = ( ! empty( $item_variation_id ) && function_exists( 'wc_get_product' ) ) ? wc_get_product( $item_variation_id ) : null;
						$is_callable_item_product_get_meta   = $this->is_callable( $item_product, 'get_meta' );
						$is_callable_item_variation_get_meta = $this->is_callable( $item_variation, 'get_meta' );
						if ( ! empty( $item_variation_id ) ) {
							$coupon_titles = ( true === $is_callable_item_variation_get_meta ) ? $item_variation->get_meta( '_coupon_title' ) : get_post_meta( $item_variation_id, '_coupon_title', true );
							if ( empty( $coupon_titles ) ) {
								$send_coupons_on_renewals = ( true === $is_callable_item_product_get_meta ) ? $item_product->get_meta( 'send_coupons_on_renewals' ) : get_post_meta( $item_product_id, 'send_coupons_on_renewals', true );
							} else {
								$send_coupons_on_renewals = ( true === $is_callable_item_variation_get_meta ) ? $item_variation->get_meta( 'send_coupons_on_renewals' ) : get_post_meta( $item_variation_id, 'send_coupons_on_renewals', true );
							}
						} elseif ( ! empty( $item_product_id ) ) {
							$send_coupons_on_renewals = ( true === $is_callable_item_product_get_meta ) ? $item_product->get_meta( 'send_coupons_on_renewals' ) : get_post_meta( $item_product_id, 'send_coupons_on_renewals', true );
						} else {
							continue;
						}
						if ( 'yes' === $send_coupons_on_renewals ) {
							$is_recursive = true;
							break;  // if in any order item recursive is enabled, it will set coupon_sent as 'no'.
						}
					}
				}
				$renewal_order_id                      = absint( $renewal_order_id );
				$renewal_order                         = ( ! empty( $renewal_order_id ) && function_exists( 'wc_get_order' ) ) ? wc_get_order( $renewal_order_id ) : null;
				$is_callable_renewal_order_update_meta = $this->is_callable( $renewal_order, 'update_meta_data' );

				$stop_recursive_coupon_generation = get_option( 'stop_recursive_coupon_generation', 'no' );
				if ( ( empty( $stop_recursive_coupon_generation ) || 'no' === $stop_recursive_coupon_generation ) && $is_recursive ) {
					if ( true === $is_callable_renewal_order_update_meta ) {
						$renewal_order->update_meta_data( 'coupon_sent', 'no' );
					} else {
						update_post_meta( $renewal_order_id, 'coupon_sent', 'no' );
					}
				} else {
					if ( true === $is_callable_renewal_order_update_meta ) {
						$renewal_order->update_meta_data( 'coupon_sent', 'yes' );
					} else {
						update_post_meta( $renewal_order_id, 'coupon_sent', 'yes' );
					}
				}

				if ( $this->is_callable( $renewal_order, 'save' ) ) {
					$renewal_order->save();
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $order_items;
		}

		/**
		 * Get order item subtotal
		 *
		 * @param  WC_Order_Item_Product $order_item The order item.
		 * @return mixed
		 */
		public function sc_get_order_item_subtotal( $order_item = null ) {
			if ( is_object( $order_item ) && is_callable( array( $order_item, 'get_total' ) ) ) {
				return $order_item->get_total();
			}
			return floatval( 0 );
		}

		/**
		 * Function to modify order_items of renewal order
		 *
		 * @param array  $order_items Associative array of order items.
		 * @param int    $original_order_id Post ID of the order being used to purchased the subscription being renewed.
		 * @param int    $renewal_order_id Post ID of the order created for renewing the subscription.
		 * @param int    $product_id ID of the product being renewed.
		 * @param string $new_order_role The role the renewal order is taking, one of 'parent' or 'child'.
		 * @return array $order_items
		 */
		public function sc_subscriptions_renewal_order_items( $order_items = null, $original_order_id = 0, $renewal_order_id = 0, $product_id = 0, $new_order_role = null ) {
			try {
				if ( empty( $original_order_id ) && empty( $renewal_order_id ) ) {
					return $order_items;
				}

				if ( empty( $original_order_id ) ) {
					$original_order_id = $this->get_first_order_id( $renewal_order_id );
					if ( empty( $original_order_id ) ) {
						return $order_items;
					}
				}

				if ( self::is_wcs_gte( '2.0.0' ) ) {
					$is_subscription_order = wcs_order_contains_subscription( $original_order_id );
				} else {
					$is_subscription_order = WC_Subscriptions_Order::order_contains_subscription( $original_order_id );
				}
				if ( $is_subscription_order ) {
					$return = false;
				} else {
					$return = true;
				}
				if ( $return ) {
					return $order_items;
				}

				$pay_from_credit_of_original_order = get_option( 'pay_from_smart_coupon_of_original_order', 'yes' );

				if ( 'child' !== $new_order_role ) {
					return $order_items;
				}
				if ( empty( $renewal_order_id ) || empty( $original_order_id ) ) {
					return $order_items;
				}

				$original_order = wc_get_order( $original_order_id );
				$renewal_order  = wc_get_order( $renewal_order_id );

				$subscriptions = wcs_get_subscriptions_for_order( $original_order, array( 'order_type' => 'parent' ) );
				reset( $subscriptions );
				$subscription = current( $subscriptions );

				$coupon_used_in_original_order = $this->get_coupon_codes( $original_order );
				$coupon_used_in_renewal_order  = $this->get_coupon_codes( $renewal_order );

				if ( $this->is_wc_gte_30() ) {
					$renewal_order_billing_email = ( is_callable( array( $renewal_order, 'get_billing_email' ) ) ) ? $renewal_order->get_billing_email() : '';
				} else {
					$renewal_order_billing_email = ( ! empty( $renewal_order->billing_email ) ) ? $renewal_order->billing_email : '';
				}

				$all_coupons = array_merge( $coupon_used_in_original_order, $coupon_used_in_renewal_order );
				$all_coupons = array_unique( $all_coupons );

				if ( count( $all_coupons ) > 0 ) {
					$apply_before_tax = get_option( 'woocommerce_smart_coupon_apply_before_tax', 'no' );

					$smart_coupons_contribution = array();
					foreach ( $all_coupons as $coupon_code ) {
						$coupon = new WC_Coupon( $coupon_code );
						if ( $this->is_wc_gte_30() ) {
							$discount_type       = $coupon->get_discount_type();
							$coupon_product_ids  = $coupon->get_product_ids();
							$coupon_category_ids = $coupon->get_product_categories();
						} else {
							$discount_type       = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
							$coupon_product_ids  = ( ! empty( $coupon->product_ids ) ) ? $coupon->product_ids : array();
							$coupon_category_ids = ( ! empty( $coupon->product_categories ) ) ? $coupon->product_categories : array();
						}

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

						if ( ! empty( $discount_type ) && 'smart_coupon' === $discount_type && ! empty( $coupon_amount ) ) {
							if ( 'yes' !== $pay_from_credit_of_original_order && $this->sc_coupon_code_exists( $coupon_code, $coupon_used_in_original_order ) ) {
								continue;
							}
							if ( $this->is_wc_gte_30() && 'yes' === $apply_before_tax ) {
								$renewal_order_items = ( is_object( $subscription ) && is_callable( array( $subscription, 'get_items' ) ) ) ? $subscription->get_items( 'line_item' ) : array();
								if ( empty( $renewal_order_items ) ) {
									break;
								}
								$subtotal              = 0;
								$items_to_apply_credit = array();
								if ( count( $coupon_product_ids ) > 0 || count( $coupon_category_ids ) > 0 ) {
									foreach ( $renewal_order_items as $renewal_order_item_id => $renewal_order_item ) {
										$renewal_product_id   = ( is_object( $renewal_order_item ) && is_callable( array( $renewal_order_item, 'get_product_id' ) ) ) ? $renewal_order_item->get_product_id() : $renewal_order_item['product_id'];
										$renewal_variation_id = ( is_object( $renewal_order_item ) && is_callable( array( $renewal_order_item, 'get_variation_id' ) ) ) ? $renewal_order_item->get_variation_id() : $renewal_order_item['variation_id'];
										$product_category_ids = wc_get_product_cat_ids( $renewal_product_id );
										if ( count( $coupon_product_ids ) > 0 && count( $coupon_category_ids ) > 0 ) {
											if ( ( in_array( $renewal_product_id, $coupon_product_ids, true ) || in_array( $renewal_variation_id, $coupon_product_ids, true ) ) && count( array_intersect( $product_category_ids, $coupon_category_ids ) ) > 0 ) {
												$items_to_apply_credit[ $renewal_order_item_id ] = $renewal_order_item;
											}
										} else {
											if ( in_array( $renewal_product_id, $coupon_product_ids, true ) || in_array( $renewal_variation_id, $coupon_product_ids, true ) || count( array_intersect( $product_category_ids, $coupon_category_ids ) ) > 0 ) {
												$items_to_apply_credit[ $renewal_order_item_id ] = $renewal_order_item;
											}
										}
									}
								} else {
									$items_to_apply_credit = $renewal_order_items;
								}
								if ( empty( $items_to_apply_credit ) ) {
									continue;
								}
								$subtotal = array_sum( array_map( array( $this, 'sc_get_order_item_subtotal' ), $items_to_apply_credit ) );
								if ( $subtotal <= 0 ) {
									continue;
								}
								if ( ! class_exists( 'WC_SC_Apply_Before_Tax' ) ) {
									include_once WC_SC_PLUGIN_DIRPATH . 'includes/class-wc-sc-apply-before-tax.php';
								}
								$sc_apply_before_tax = WC_SC_Apply_Before_Tax::get_instance();
								foreach ( $renewal_order_items as $renewal_order_item_id => $renewal_order_item ) {
									if ( array_key_exists( $renewal_order_item_id, $items_to_apply_credit ) ) {
										$discounting_amount = $renewal_order_item->get_total();
										$quantity           = $renewal_order_item->get_quantity();
										$discount           = $sc_apply_before_tax->sc_get_discounted_price( $discounting_amount, $quantity, $subtotal, $coupon_amount );
										$discount          *= $quantity;
										$renewal_order_items[ $renewal_order_item_id ]->set_total( $discounting_amount - $discount );
									}
								}
								$renewal_order_total = $subtotal;
								$order_items         = $renewal_order_items;

								$discount = min( $renewal_order_total, $coupon_amount );
							} else {
								$renewal_order_total               = $renewal_order->get_total();
								$renewal_total_tax                 = $renewal_order->get_total_tax();
								$renewal_order_total_excluding_tax = $renewal_order_total - $renewal_total_tax;

								$discount       = min( $renewal_order_total_excluding_tax, $coupon_amount );
								$coupon_amount -= $discount;
								if ( $this->is_callable( $renewal_order, 'set_discount_total' ) ) {
									$renewal_order->set_discount_total( $discount );
								}
								if ( $coupon_amount > 0 ) {
									$discount_tax   = min( $renewal_total_tax, $coupon_amount );
									$coupon_amount -= $discount_tax;
									if ( $this->is_callable( $renewal_order, 'set_discount_tax' ) ) {
										$renewal_order->set_discount_tax( $discount_tax );
									}
									$discount += $discount_tax;
								}
							}

							if ( $discount > 0 ) {
								$new_order_total = $renewal_order_total - $discount;
								$this->update_post_meta( $renewal_order_id, '_order_total', $new_order_total, true, $renewal_order );
								$this->update_post_meta( $renewal_order_id, '_order_discount', $discount, true, $renewal_order );
								if ( $new_order_total <= floatval( 0 ) ) {
									if ( $this->is_callable( $renewal_order, 'update_meta_data' ) && $this->is_callable( $renewal_order, 'save' ) ) {
										$renewal_order->update_meta_data( '_renewal_paid_by_smart_coupon', 'yes' );
										$renewal_order->save();
									} else {
										update_post_meta( $renewal_order_id, '_renewal_paid_by_smart_coupon', 'yes' );
									}
								}
								if ( $this->is_wc_gte_30() ) {
									$item = new WC_Order_Item_Coupon();
									$item->set_props(
										array(
											'code'     => $coupon_code,
											'discount' => $discount,
											'order_id' => ( is_object( $renewal_order ) && is_callable( array( $renewal_order, 'get_id' ) ) ) ? $renewal_order->get_id() : 0,
										)
									);
									$item->save();
									$renewal_order->add_item( $item );
								} else {
									$renewal_order->add_coupon( $coupon_code, $discount );
								}
								$smart_coupons_contribution[ $coupon_code ] = $discount;
							}
						}
					}
					if ( ! empty( $smart_coupons_contribution ) ) {
						$this->update_post_meta( $renewal_order_id, 'smart_coupons_contribution', $smart_coupons_contribution, true, $renewal_order );
						$renewal_order->sc_total_credit_used = $smart_coupons_contribution;
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $order_items;
		}

		/**
		 * Function to trigger complete payment for renewal if it's paid by Smart Coupons
		 *
		 * @param WC_Order $renewal_order Order created on subscription renewal.
		 * @param WC_Order $original_order Order being used to purchased the subscription.
		 * @param int      $product_id ID of the product being renewed.
		 * @param string   $new_order_role The role the renewal order is taking, one of 'parent' or 'child'.
		 */
		public function sc_renewal_complete_payment( $renewal_order = null, $original_order = null, $product_id = 0, $new_order_role = null ) {
			try {
				global $store_credit_label;

				if ( $this->is_wc_gte_30() ) {
					$renewal_order_id = ( is_object( $renewal_order ) && is_callable( array( $renewal_order, 'get_id' ) ) ) ? $renewal_order->get_id() : 0;
				} else {
					$renewal_order_id = ( ! empty( $renewal_order->id ) ) ? $renewal_order->id : 0;
				}

				if ( empty( $renewal_order_id ) ) {
					return;
				}
				if ( self::is_wcs_gte( '2.0.0' ) ) {
					$is_renewal_order = wcs_order_contains_renewal( $renewal_order_id );
				} else {
					$is_renewal_order = WC_Subscriptions_Renewal_Order::is_renewal( $renewal_order_id );
				}
				if ( $is_renewal_order ) {
					$return = false;
				} else {
					$return = true;
				}
				if ( $return ) {
					return;
				}

				$order_needs_processing = false;

				if ( count( $renewal_order->get_items() ) > 0 ) {
					foreach ( $renewal_order->get_items() as $item ) {
						$_product = ( is_object( $item ) && is_callable( array( $item, 'get_product' ) ) ) ? $item->get_product() : $renewal_order->get_product_from_item( $item );

						if ( $_product instanceof WC_Product ) {
							$virtual_downloadable_item = $_product->is_downloadable() && $_product->is_virtual();

							if ( apply_filters( 'woocommerce_order_item_needs_processing', ! $virtual_downloadable_item, $_product, $renewal_order_id ) ) {
								$order_needs_processing = true;
								break;
							}
						} else {
							$order_needs_processing = true;
							break;
						}
					}
				}

				if ( $this->is_callable( $renewal_order, 'meta_exists' ) && true !== $renewal_order->meta_exists( '_renewal_paid_by_smart_coupon' ) ) {
					$renewal_order->read_meta_data( true );
				}

				$is_renewal_paid_by_smart_coupon = ( $this->is_callable( $renewal_order, 'get_meta' ) ) ? $renewal_order->get_meta( '_renewal_paid_by_smart_coupon' ) : get_post_meta( $renewal_order_id, '_renewal_paid_by_smart_coupon', true );
				if ( ! empty( $is_renewal_paid_by_smart_coupon ) && 'yes' === $is_renewal_paid_by_smart_coupon ) {

					/* translators: %s: singular name for store credit */
					$order_paid_txt = ! empty( $store_credit_label['singular'] ) ? sprintf( __( 'Order paid by %s', 'woocommerce-smart-coupons' ), $store_credit_label['singular'] ) : __( 'Order paid by store credit.', 'woocommerce-smart-coupons' );
					$renewal_order->update_status( apply_filters( 'woocommerce_payment_complete_order_status', $order_needs_processing ? 'processing' : 'completed', $renewal_order_id, $renewal_order ), $order_paid_txt ); // HN WC SA Support #7485.
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Function to show gift certificate received details form based on product type
		 *
		 * @param  boolean $is_show Whether to show or not.
		 * @param  array   $args    Additional arguments.
		 * @return boolean          [description]
		 */
		public function is_show_gift_certificate_receiver_detail_form( $is_show = false, $args = array() ) {

			if ( wcs_cart_contains_renewal() ) {
				return false;
			}

			return $is_show;
		}

		/**
		 * Function to add subscription specific settings
		 *
		 * @param  array $settings Existing settings.
		 * @return array  $settings
		 */
		public function smart_coupons_settings( $settings = array() ) {
			global $store_credit_label;

			$singular = ( ! empty( $store_credit_label['singular'] ) ) ? $store_credit_label['singular'] : __( 'store credit', 'woocommerce-smart-coupons' );

			$wc_subscriptions_options = array(
				array(
					'name'          => __( 'Recurring subscriptions', 'woocommerce-smart-coupons' ),
					/* translators: %s: Label for store credit */
					'desc'          => sprintf( __( 'Use %s applied in first subscription order for subsequent renewals until credit reaches zero', 'woocommerce-smart-coupons' ), strtolower( $singular ) ),
					'id'            => 'pay_from_smart_coupon_of_original_order',
					'type'          => 'checkbox',
					'default'       => 'no',
					'checkboxgroup' => 'start',
					'autoload'      => false,
				),
				array(
					'desc'          => __( 'Renewal orders should not generate coupons even when they include a product that issues coupons', 'woocommerce-smart-coupons' ),
					'id'            => 'stop_recursive_coupon_generation',
					'type'          => 'checkbox',
					'default'       => 'no',
					'checkboxgroup' => 'end',
					'autoload'      => false,
				),
			);

			array_splice( $settings['general']['fields'], 9, 0, $wc_subscriptions_options );

			return $settings;

		}

		/**
		 * Whether to bypass coupon removal from recurring item
		 *
		 * @param  boolean   $bypass           Bypass or not.
		 * @param  WC_Coupon $coupon           The coupon object.
		 * @param  string    $coupon_type      The discount type.
		 * @param  string    $calculation_type The calculation type of subscription.
		 * @return boolean   $bypass           Bypass or not
		 */
		public function bypass_removal_of_coupon_having_coupon_actions( $bypass = false, $coupon = null, $coupon_type = '', $calculation_type = '' ) {
			try {
				if ( $this->is_wc_gte_30() ) {
					$coupon_code = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_code' ) ) ) ? $coupon->get_code() : '';
				} else {
					$coupon_code = ( ! empty( $coupon->code ) ) ? $coupon->code : '';
				}

				if ( ! class_exists( 'WC_SC_Coupon_Actions' ) ) {
					include_once WC_SC_PLUGIN_DIRPATH . 'includes/class-wc-sc-coupon-actions.php';
				}

				$wc_sc_coupon_actions = WC_SC_Coupon_Actions::get_instance();

				$coupon_actions = $wc_sc_coupon_actions->get_coupon_actions( $coupon_code );

				if ( false === $bypass && ! empty( $coupon_actions ) ) {
					$coupon        = new WC_Coupon( $coupon_code );
					$discount_type = $coupon->get_discount_type();
					if ( 'smart_coupon' === $discount_type ) {
						return true;
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $bypass;
		}

		/**
		 * Modify recurring cart
		 * Specifically, remove coupons having coupon actions from recurring carts
		 *
		 * @param  mixed $total The total.
		 * @return mixed $total
		 */
		public function modify_recurring_cart( $total ) {
			try {
				$recurring_carts = WC()->cart->recurring_carts;

				if ( ! empty( $recurring_carts ) ) {

					if ( ! class_exists( 'WC_SC_Coupon_Actions' ) ) {
						include_once WC_SC_PLUGIN_DIRPATH . 'includes/class-wc-sc-coupon-actions.php';
					}

					$wc_sc_coupon_actions = WC_SC_Coupon_Actions::get_instance();

					foreach ( WC()->cart->recurring_carts as $cart_item_key => $cart ) {
						if ( ! empty( $cart->applied_coupons ) ) {
							foreach ( $cart->applied_coupons as $index => $coupon_code ) {
								$coupon_actions = $wc_sc_coupon_actions->get_coupon_actions( $coupon_code );
								if ( ! empty( $coupon_actions ) ) {
									$coupon        = new WC_Coupon( $coupon_code );
									$discount_type = $coupon->get_discount_type();
									if ( 'smart_coupon' === $discount_type ) {
										unset( WC()->cart->recurring_carts[ $cart_item_key ]->applied_coupons[ $index ] );
									}
								}
							}
						}
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $total;

		}

		/**
		 * Hooks for WCS 2.3.0+
		 */
		public function hooks_for_wcs_230() {
			if ( $this->is_wcs_gte( '2.3.0' ) ) {
				add_filter( 'wc_smart_coupons_export_headers', array( $this, 'export_headers' ) );
				add_filter( 'smart_coupons_parser_postmeta_defaults', array( $this, 'postmeta_defaults' ) );
				add_filter( 'sc_generate_coupon_meta', array( $this, 'generate_coupon_meta' ), 10, 2 );
				add_action( 'wc_sc_new_coupon_generated', array( $this, 'copy_subscriptions_coupon_meta' ) );
			}
		}

		/**
		 * Add subscriptions coupon meta in export headers
		 *
		 * @param  array $headers Existing headers.
		 * @return array
		 */
		public function export_headers( $headers = array() ) {

			$action_headers = array(
				'_wcs_number_payments' => __( 'Active for x payments', 'woocommerce-smart-coupons' ),
			);

			return array_merge( $headers, $action_headers );

		}

		/**
		 * Post meta defaults for subscriptions coupon meta
		 *
		 * @param  array $defaults Existing postmeta defaults.
		 * @return array
		 */
		public function postmeta_defaults( $defaults = array() ) {

			$actions_defaults = array(
				'_wcs_number_payments' => '',
			);

			return array_merge( $defaults, $actions_defaults );
		}

		/**
		 * Add subscriptions coupons meta with value in coupon meta
		 *
		 * @param  array $data The row data.
		 * @param  array $post The POST values.
		 * @return array Modified data
		 */
		public function generate_coupon_meta( $data = array(), $post = array() ) {

			if ( isset( $post['wcs_number_payments'] ) ) {
				$data['_wcs_number_payments'] = trim( $post['wcs_number_payments'] );
			}

			return $data;
		}

		/**
		 * Function to copy subscription coupon meta in newly generated coupon
		 *
		 * @param  array $args The arguments.
		 */
		public function copy_subscriptions_coupon_meta( $args = array() ) {
			$new_coupon_id = ( ! empty( $args['new_coupon_id'] ) ) ? absint( $args['new_coupon_id'] ) : 0;
			$coupon        = ( ! empty( $args['ref_coupon'] ) ) ? $args['ref_coupon'] : false;

			if ( empty( $new_coupon_id ) || empty( $coupon ) ) {
				return;
			}

			$wcs_number_payments = '';
			if ( $this->is_wc_gte_30() ) {
				$wcs_number_payments = $coupon->get_meta( '_wcs_number_payments' );
			} else {
				$old_coupon_id       = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
				$wcs_number_payments = get_post_meta( $old_coupon_id, '_wcs_number_payments', true );
			}
			$this->update_post_meta( $new_coupon_id, '_wcs_number_payments', $wcs_number_payments );
		}

		/**
		 * Get the reference key after which the setting will be inserted
		 *
		 * @param  string $after_key The key after which the setting to be inserted.
		 * @param  array  $args      Additional arguments.
		 * @return string
		 */
		public function endpoint_account_settings_after_key( $after_key = '', $args = array() ) {
			return 'woocommerce_myaccount_subscription_payment_method_endpoint';
		}

		/**
		 * Function to change coupon display name for Subscription coupons
		 *
		 * @param string    $coupon_type The type of the coupon.
		 * @param WC_Coupon $coupon Coupon object.
		 * @param array     $all_discount_types List of available discount types.
		 * @return string
		 */
		public function valid_display_type( $coupon_type, $coupon, $all_discount_types ) {
			if ( 'Recurring Product % Discount' === $coupon_type ) {
				$coupon_type = 'Recurring Product Discount';
			} elseif ( 'Sign Up Fee % Discount' === $coupon_type ) {
				$coupon_type = 'Sign Up Fee Discount';
			}
			return $coupon_type;
		}

		/**
		 * Function to change coupon amount display for Subscription coupons
		 *
		 * @param float     $coupon_amount Coupon amount.
		 * @param WC_Coupon $coupon Coupon object.
		 * @return float
		 */
		public function valid_display_amount( $coupon_amount, $coupon ) {
			$coupon_discount_type = $coupon->get_discount_type();
			if ( 'recurring_percent' === $coupon_discount_type || 'sign_up_fee_percent' === $coupon_discount_type ) {
				$coupon_amount = $coupon_amount . '%';
			} elseif ( 'recurring_fee' === $coupon_discount_type || 'sign_up_fee' === $coupon_discount_type ) {
				$coupon_amount = wc_price( $coupon_amount );
			}
			return $coupon_amount;
		}

		/**
		 * Coupon design thumbnail src set for subscription coupons
		 *
		 * @param array $src_set Existing src set.
		 * @param array $args Additional arguments.
		 * @return array
		 */
		public function coupon_design_thumbnail_src_set( $src_set = array(), $args = array() ) {

			$coupon = ( ! empty( $args['coupon_object'] ) ) ? $args['coupon_object'] : null;
			if ( $this->is_wc_gte_30() ) {
				$discount_type = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
			} else {
				$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
			}
			if ( ! empty( $discount_type ) ) {
				switch ( $discount_type ) {
					case 'sign_up_fee':
					case 'sign_up_fee_percent':
						$src_set = array(
							'subs-discount-voucher.svg',
						);
						break;

					case 'recurring_fee':
					case 'recurring_percent':
						$src_set = array(
							'subs-calendar-discount.svg',
						);
						break;
				}
			}

			return $src_set;
		}

		/**
		 * Get percent discount types fromm subscriptions
		 *
		 * @param array $discount_types Existing discount tyeps.
		 * @param array $args Additional arguments.
		 * @return array
		 */
		public function percent_discount_types( $discount_types = array(), $args = array() ) {
			$subs_percent_discount_types = array(
				'sign_up_fee_percent',
				'recurring_percent',
			);
			$discount_types              = array_merge( $discount_types, $subs_percent_discount_types );
			return $discount_types;
		}

		/**
		 * Function to check if a coupon can be auto applied or not
		 *
		 * @param boolean $is_auto_apply Is auto apply.
		 * @param array   $args Additional arguments.
		 * @return boolean
		 */
		public function is_auto_apply( $is_auto_apply = true, $args = array() ) {

			$cart_total                 = ( ! empty( $args['cart_total'] ) ) ? floatval( $args['cart_total'] ) : 0;
			$cart_contains_subscription = self::is_cart_contains_subscription();
			if ( false === $is_auto_apply && empty( $cart_total ) && true === $cart_contains_subscription ) {
				$is_auto_apply = true;
			}

			return $is_auto_apply;
		}

		/**
		 * Function to check if cart contains subscription
		 *
		 * @return bool whether cart contains subscription or not
		 */
		public static function is_cart_contains_subscription() {
			if ( class_exists( 'WC_Subscriptions_Cart' ) && WC_Subscriptions_Cart::cart_contains_subscription() ) {
				return true;
			}
			return false;
		}

		/**
		 * Function to check WooCommerce Subscription version
		 *
		 * @param string $version Subscription version.
		 * @return bool whether passed version is greater than or equal to current version of WooCommerce Subscription
		 */
		public static function is_wcs_gte( $version = null ) {
			if ( is_null( $version ) ) {
				return false;
			}
			if ( version_compare( $version, '4.0.0', '>=' ) && class_exists( 'WC_Subscriptions_Core_Plugin' ) ) {
				return true;
			}
			if ( ! class_exists( 'WC_Subscriptions' ) || empty( WC_Subscriptions::$version ) ) {
				return false;
			}
			return version_compare( WC_Subscriptions::$version, $version, '>=' );
		}

		/**
		 * Function to modify cart for actions tab product of coupon
		 *
		 * @param WC_Subscription $subscription The subscription object. This param is unused. It is the first parameter of the hook.
		 * @param WC_Order        $order               The renewal order object.
		 */
		public function maybe_revalidate_coupon_actions( $subscription = null, $order = null ) {
			try {
				if ( is_null( $order ) ) {
					return;
				}
				if ( ! class_exists( 'WC_SC_Coupon_Actions' ) ) {
					include_once WC_SC_PLUGIN_DIRPATH . 'includes/class-wc-sc-coupon-actions.php';
				}
				$wc_sc_coupon_actions = WC_SC_Coupon_Actions::get_instance();
				$order_coupons        = ( $this->is_callable( $order, 'get_used_coupons' ) ) ? $order->get_used_coupons() : array();
				if ( empty( $order_coupons ) ) {
					return;
				}

				$product_ids_added_by_coupon = array();
				$is_order_updated            = false;

				foreach ( $order_coupons as $coupon_code ) {
					$coupon_actions = ( $this->is_callable( $wc_sc_coupon_actions, 'get_coupon_actions' ) ) ? $wc_sc_coupon_actions->get_coupon_actions( $coupon_code ) : array();
					if ( ! empty( $coupon_actions ) && is_array( $coupon_actions ) ) {
						$product_ids_added_by_coupon = wp_list_pluck( $coupon_actions, 'product_id' );
					} else {
						$product_ids_added_by_coupon = array();
					}
					if ( empty( $product_ids_added_by_coupon ) ) {
						continue;
					}
					$order_items = ( $this->is_callable( $order, 'get_items' ) ) ? $order->get_items() : array();
					if ( ! empty( $order_items ) && ! is_scalar( $order_items ) ) {
						foreach ( $order_items as $item_id => $item ) {
							$wc_sc_product_coupon = $this->is_callable( $item, 'get_meta' ) ? $item->get_meta( '_wc_sc_product_source' ) : '';
							if ( empty( $wc_sc_product_coupon ) ) {
								continue;
							}
							$item_product_id = ( $this->is_callable( $item, 'get_product_id' ) ) ? $item->get_product_id() : 0;
							if ( empty( $item_product_id ) ) {
								continue;
							}
							$product_ids_added_by_coupon = array_map( 'absint', $product_ids_added_by_coupon );
							if ( $this->sc_is_same_coupon_code( $coupon_code, $wc_sc_product_coupon ) && in_array( absint( $item_product_id ), $product_ids_added_by_coupon, true ) ) {
								$order->remove_item( $item_id );
								$is_order_updated = true;
							}
						}
					}
				}

				if ( true === $is_order_updated ) {
					$order->save();
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Enqueue styles & scripts
		 */
		public function enqueue_styles_scripts() {
			if ( ! class_exists( 'WC_Subscriptions_Core_Plugin' ) ) {
				return;
			}
			if ( ! is_callable( 'WC_Subscriptions_Core_Plugin::instance' ) ) {
				return;
			}
			$wc_subscriptions_core_plugin_instance = WC_Subscriptions_Core_Plugin::instance();
			// Get the script version.
			$ver = ( $this->is_callable( $wc_subscriptions_core_plugin_instance, 'get_library_version' ) ) ? $wc_subscriptions_core_plugin_instance->get_library_version() : false;
			if ( empty( $ver ) ) {
				$ver = ( $this->is_callable( $wc_subscriptions_core_plugin_instance, 'get_plugin_version' ) ) ? $wc_subscriptions_core_plugin_instance->get_plugin_version() : false;
			}
			// Get admin screen ID.
			$screen    = get_current_screen();
			$screen_id = isset( $screen->id ) ? $screen->id : '';

			if ( is_admin() && in_array( $screen_id, array( 'marketing_page_wc-smart-coupons' ), true ) ) {
				wp_enqueue_script(
					'wcs-admin-coupon-meta-boxes',
					WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/meta-boxes-coupon.js' ),
					array( 'jquery', 'wc-admin-meta-boxes' ),
					$ver,
					false
				);

			}
		}

		/**
		 * Add option
		 *
		 * @param array $args Additional arguments.
		 */
		public function add_option( $args = array() ) {
			add_option( 'stop_recursive_coupon_generation', 'no', '', 'no' );
		}

		/**
		 * Add system status
		 *
		 * @param array $items Current items.
		 * @param array $args Additional arguments.
		 * @return array $items
		 */
		public function system_status_items( $items = array(), $args = array() ) {
			$source                           = $args['source'] ?? null;
			$stop_recursive_coupon_generation = get_option( 'stop_recursive_coupon_generation' );
			$items[ __( 'Renewal orders should not generate coupons even when they include a product that issues coupons', 'woocommerce-smart-coupons' ) ] = ( ! empty( $source ) && is_callable( array( $source, 'iconify' ) ) ) ? $source->iconify( $stop_recursive_coupon_generation ) : '';
			return $items;
		}

		/**
		 * Modify renewal order created via store API
		 *
		 * @param WC_Order $renewal_order The renewal order object.
		 */
		public function modify_store_api_renewal_order( $renewal_order ) {
			try {
				if ( ! function_exists( 'wcs_is_frontend_request' ) || ! function_exists( 'wcs_is_checkout_blocks_api_request' ) || ! function_exists( 'wcs_order_contains_renewal' ) || ! function_exists( 'wcs_order_contains_early_renewal' ) || ! function_exists( 'wcs_get_subscription' ) || ! function_exists( 'wcs_get_objects_property' ) ) {
					return;
				}

				if ( wcs_is_frontend_request() || wcs_is_checkout_blocks_api_request() ) {
					if ( wcs_order_contains_renewal( $renewal_order ) && wcs_order_contains_early_renewal( $renewal_order ) ) {
						$subscription          = wcs_get_subscription( wcs_get_objects_property( $renewal_order, 'subscription_renewal_early' ) );
						$subscription_order    = ( $this->is_callable( $subscription, 'get_parent' ) ) ? $subscription->get_parent() : null;
						$subscription_order_id = ( ! empty( $subscription_order ) && $this->is_callable( $subscription_order, 'get_id' ) ) ? $subscription_order->get_id() : 0;
						$renewal_order_id      = ( ! empty( $renewal_order ) && $this->is_callable( $renewal_order, 'get_id' ) ) ? $renewal_order->get_id() : 0;
						$order_items           = ( $this->is_callable( $renewal_order, 'get_items' ) ) ? $renewal_order->get_items() : array();
						$order_items           = $this->sc_modify_renewal_order( $order_items, $subscription_order_id, $renewal_order_id );
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Disable auto-generation of coupon for subscription switch order items.
		 *
		 * Prevents generating a coupon when the order item is part of a subscription switch.
		 *
		 * @param bool  $is_auto_generate Whether the coupon should be auto-generated.
		 * @param array $context          Context data including order_id, order_item, etc.
		 *
		 * @return bool
		 */
		public function disable_auto_generate_coupon_for_switch_subscription_item( $is_auto_generate, $context ) {
			if ( empty( $context['order_id'] ) || empty( $context['order_item'] ) ) {
				return $is_auto_generate;
			}

			// Ensure required function exists.
			if ( ! function_exists( 'wcs_order_contains_switch' ) ) {
				return $is_auto_generate;
			}

			$order_id   = $context['order_id'];
			$order_item = $context['order_item'];

			if ( ! $order_item instanceof WC_Order_Item_Product ) {
				return $is_auto_generate;
			}

			// Check if order contains a subscription switch.
			$is_switch_order = wcs_order_contains_switch( $order_id );

			// Retrieve switch meta from the order item.
			if ( $this->is_wc_gte_30() ) {
				$subscription_switch_meta = $order_item->get_meta( '_cart_item_key_subscription_switch', true );
			} else {
				$subscription_switch_meta = $this->get_order_item_meta( $order_item, '_cart_item_key_subscription_switch', true );
			}

			// Disable auto-generation if it is a switch subscription item.
			if ( ! empty( $subscription_switch_meta ) && $is_switch_order ) {
				return false;
			}

			return $is_auto_generate;
		}

	}

}

WCS_SC_Compatibility::get_instance();
