<?php
/**
 * Purchase Credit Features
 *
 * @author      StoreApps
 * @since       3.3.0
 * @version     3.13.1
 *
 * @package     woocommerce-smart-coupons/includes/
 */

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

if ( ! class_exists( 'WC_SC_Purchase_Credit' ) ) {

	/**
	 * Class for handling Purchase credit feature
	 */
	class WC_SC_Purchase_Credit {

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

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

			add_action( 'woocommerce_before_add_to_cart_form', array( $this, 'call_for_credit_form' ), 20 );
			add_filter( 'woocommerce_call_for_credit_form_template', array( $this, 'woocommerce_call_for_credit_form_template_path' ) );

			add_filter( 'woocommerce_is_purchasable', array( $this, 'make_product_purchasable' ), 10, 2 );
			add_filter( 'woocommerce_get_price_html', array( $this, 'price_html_for_purchasing_credit' ), 10, 2 );
			add_action( 'woocommerce_before_calculate_totals', array( $this, 'override_price_before_calculate_totals' ) );

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

			if ( is_plugin_active( 'woocommerce-gateway-paypal-express/woocommerce-gateway-paypal-express.php' ) ) {
				add_action( 'woocommerce_ppe_checkout_order_review', array( $this, 'gift_certificate_receiver_detail_form' ) );
				add_action( 'woocommerce_ppe_do_payaction', array( $this, 'ppe_save_called_credit_details_in_order' ) );
			}

			add_filter( 'woocommerce_cart_item_price', array( $this, 'woocommerce_cart_item_price_html' ), 10, 3 );
			add_action( 'woocommerce_checkout_after_customer_details', array( $this, 'gift_certificate_receiver_detail_form' ) );

			add_action( 'wp_loaded', array( $this, 'purchase_credit_hooks' ) );

			add_action( 'woocommerce_checkout_order_processed', array( $this, 'save_called_credit_details_in_order' ), 10, 2 );
			add_filter( 'woocommerce_add_cart_item_data', array( $this, 'call_for_credit_cart_item_data' ), 10, 3 );
			add_action( 'woocommerce_add_to_cart', array( $this, 'save_called_credit_in_session' ), 10, 6 );

			add_filter( 'woocommerce_product_get_price', array( $this, 'override_voucher_product_empty_price' ), 9, 2 );

			add_action( 'wp_footer', array( $this, 'enqueue_styles_scripts' ) );

			add_action( 'woocommerce_cart_is_empty', array( $this, 'maybe_clear_credit_called_session' ) );

			add_action( 'woocommerce_after_checkout_validation', array( $this, 'maybe_required_coupon_delivery_date_time' ), 10, 2 );
			add_action( 'woocommerce_after_checkout_validation', array( $this, 'save_coupon_receiver_details_in_session' ), 99, 2 );

			add_action( 'woocommerce_order_status_completed', array( $this, 'cleanup_order_item_meta' ), 9999 );

			add_filter( 'woocommerce_update_order_review_fragments', array( $this, 'update_order_review_fragments' ) );
			add_action( 'wc_ajax_wc_sc_save_coupon_receiver_details', array( $this, 'ajax_save_coupon_receiver_details' ) );
			add_action( 'woocommerce_cart_emptied', array( $this, 'maybe_clear_coupon_receiver_details_session' ) );

			add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'save_called_credit_details_in_order_via_store_api' ) );

			// Product page hooks.
			add_action( 'woocommerce_before_add_to_cart_button', array( $this, 'product_page_gift_certificate_receiver_detail_form' ), 20 );
			add_action( 'woocommerce_add_to_cart', array( $this, 'move_product_page_session_to_checkout' ), 10, 6 );

			// AJAX hooks for saving gift receiver details.
			add_action( 'wp_ajax_wc_sc_save_product_page_coupon_receiver_details', array( $this, 'ajax_save_product_page_coupon_receiver_details' ) );
			add_action( 'wp_ajax_nopriv_wc_sc_save_product_page_coupon_receiver_details', array( $this, 'ajax_save_product_page_coupon_receiver_details' ) );

			// Enqueue timepicker scripts on product pages.
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_product_page_timepicker' ), 20 );

			// Ensure WooCommerce session is initialized early on product pages.
			add_action( 'template_redirect', array( $this, 'maybe_init_wc_session' ), 1 );

			// Enqueue scripts and styles for product page.
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_product_page_gift_form_assets' ) );
		}

		/**
		 * Get single instance of WC_SC_Purchase_Credit
		 *
		 * @return WC_SC_Purchase_Credit Singleton object of WC_SC_Purchase_Credit
		 */
		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 The function name.
		 * @param array  $arguments Array of arguments passed while calling $function_name.
		 * @return mixed 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 form to enter value of the store credit to be purchased
		 */
		public function call_for_credit_form() {
			try {
				global $product, $store_credit_label;

				if ( $product instanceof WC_Product_Variation ) {
					return;
				}

				if ( $this->is_wc_gte_30() ) {
					if ( ! is_object( $product ) || ! is_callable( array( $product, 'get_id' ) ) ) {
						return;
					}
					$product_id = $product->get_id();
					if ( empty( $product_id ) ) {
						return;
					}
				} else {
					$product_id = ( ! empty( $product->id ) ) ? $product->id : 0;
				}

				$coupons = $this->get_coupon_titles( array( 'product_object' => $product ) );

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

				$product_price = $product->get_price();

				$_nyp = ( $this->is_callable( $product, 'get_meta' ) ) ? $product->get_meta( '_nyp' ) : get_post_meta( $product_id, '_nyp', true );

				// MADE CHANGES IN THE CONDITION TO SHOW INPUT FIELD FOR PRICE ONLY FOR COUPON AS A PRODUCT.
				if ( ! empty( $coupons ) && $this->is_coupon_amount_pick_from_product_price( $coupons ) && ( ! ( ! empty( $product_price ) || ( is_plugin_active( 'woocommerce-name-your-price/woocommerce-name-your-price.php' ) && ( 'yes' === $_nyp ) ) ) ) ) {

					wp_register_script( 'wc-smart-coupons-call-for-credit', '', array(), $this->get_smart_coupons_version(), true );
					wp_enqueue_script( 'wc-smart-coupons-call-for-credit' );

					$js = "
								const minCreditAmount      = parseFloat( jQuery('input#credit_called').attr('min') );
								const maxCreditAmount      = parseFloat( jQuery('input#credit_called').attr('max') );
								var   validateCreditCalled = function(){
									var enteredCreditAmount  = parseFloat( jQuery('input#credit_called').val() );
									if ( isNaN(enteredCreditAmount) || enteredCreditAmount < minCreditAmount || ( maxCreditAmount > 0 && enteredCreditAmount > maxCreditAmount ) ) {
										var creditErrorMsg = '" . __( 'Invalid amount.', 'woocommerce-smart-coupons' ) . "';
										if ( isNaN(enteredCreditAmount) ) {
											creditErrorMsg += ' " . __( 'Enter a numeric value.', 'woocommerce-smart-coupons' ) . "';
										}
										if ( enteredCreditAmount < minCreditAmount ) {
											creditErrorMsg += ' " . __( 'The value should not be less than', 'woocommerce-smart-coupons' ) . " ' + minCreditAmount;
										} else if ( enteredCreditAmount > maxCreditAmount ) {
											creditErrorMsg += ' " . __( 'The value should not be greater than', 'woocommerce-smart-coupons' ) . " ' + maxCreditAmount;
										}
										jQuery('#error_message').text(creditErrorMsg);
										jQuery('input#credit_called').css('border-color', 'red');
										return false;
									} else {
										jQuery('form.cart').unbind('submit');
										jQuery('#error_message').text('');
										jQuery('input#credit_called').css('border-color', '');
										return true;
									}
								};

								jQuery('input#credit_called').bind('change keyup', function(){
									validateCreditCalled();
									jQuery('input#hidden_credit').remove();
									if ( jQuery('input[name=quantity]').length ) {
										jQuery('input[name=quantity]').append('<input type=\"hidden\" id=\"hidden_credit\" name=\"credit_called[" . absint( $product_id ) . "]\" value=\"'+jQuery('input#credit_called').val()+'\" />');
									} else {
										jQuery('input[name=\"add-to-cart\"]').after('<input type=\"hidden\" id=\"hidden_credit\" name=\"credit_called[" . absint( $product_id ) . "]\" value=\"'+jQuery('input#credit_called').val()+'\" />');
									}
								});

								jQuery('button.single_add_to_cart_button').on('click', function(e) {
									if ( validateCreditCalled() == false ) {
										e.preventDefault();
									}
								});

								jQuery('input#credit_called').on( 'keypress', function (e) {
									if (e.which == 13) {
										jQuery('form.cart').find('button[name=\"add-to-cart\"]').trigger('click');
									}
								});

								// To handle, if the call for credit form is included twice.
								jQuery.each( jQuery('body').find('div#call_for_credit'), function(){
									let current_element = jQuery(this);
									let is_visible = current_element.is(':visible');
									if ( false === is_visible ) {
										current_element.remove();
									}
								});

							";

					// To handle, if the call for credit form is included twice.
					if ( did_action( 'wc_sc_call_for_credit_script_enqueued' ) <= 0 ) {
						wp_add_inline_script( 'wc-smart-coupons-call-for-credit', $js );
						do_action( 'wc_sc_call_for_credit_script_enqueued', array( 'source' => $this ) );
					}

					$smart_coupon_store_gift_page_text = get_option( 'smart_coupon_store_gift_page_text' );

					/* translators: %s: singular name for store credit */
					$smart_coupon_store_gift_page_text = ( ! empty( $smart_coupon_store_gift_page_text ) ) ? $smart_coupon_store_gift_page_text . ' ' : ( ! empty( $store_credit_label['singular'] ) ? sprintf( __( 'Purchase %s worth', 'woocommerce-smart-coupons' ), ucwords( $store_credit_label['singular'] ) ) : __( 'Purchase credit worth', 'woocommerce-smart-coupons' ) ) . ' ';

					$custom_classes = array(
						'container' => '',
						'row'       => '',
						'label'     => '',
						'input'     => '',
						'error'     => '',
					);

					$custom_classes = apply_filters( 'wc_sc_call_for_credit_template_custom_classes', $custom_classes );

					$currency_symbol = get_woocommerce_currency_symbol();

					$input = array(
						'type'         => 'number',
						'autocomplete' => 'off',
						'autofocus'    => 'autofocus',
						'height'       => '',
						'max'          => '',
						'maxlength'    => '',
						'min'          => '1',
						'minlength'    => '',
						'name'         => '',
						'pattern'      => '',
						'placeholder'  => '',
						'required'     => 'required',
						'size'         => '',
						'step'         => 'any',
						'width'        => '',
						'class'        => 'input-text',
					);

					$input = apply_filters( 'wc_sc_call_for_credit_template_input', $input, array( 'source' => $this ) );

					$input = array_filter( $input );

					$input['id']    = 'credit_called';
					$input['name']  = $input['id'];
					$input['value'] = '';

					$allowed_html = wp_kses_allowed_html( 'post' );

					$allowed_html['input'] = array(
						'aria-describedby' => true,
						'aria-details'     => true,
						'aria-label'       => true,
						'aria-labelledby'  => true,
						'aria-hidden'      => true,
					);
					$input_element         = '<input ';
					foreach ( $input as $attribute => $value ) {
						$input_element                      .= $attribute . '="' . esc_attr( $value ) . '" ';
						$allowed_html['input'][ $attribute ] = true;
					}
					$input_element .= ' />';

					if ( function_exists( 'wc_get_template' ) ) {
						$args = array(
							'custom_classes'  => $custom_classes,
							'currency_symbol' => $currency_symbol,
							'smart_coupon_store_gift_page_text' => $smart_coupon_store_gift_page_text,
							'allowed_html'    => $allowed_html,
							'input'           => $input,
							'input_element'   => $input_element,
						);
						wc_get_template( 'call-for-credit-form.php', $args, '', plugin_dir_path( WC_SC_PLUGIN_FILE ) . 'templates/' );
					} else {
						include apply_filters( 'woocommerce_call_for_credit_form_template', 'templates/call-for-credit-form.php' );
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Allow overriding of Smart Coupon's template for credit of any amount
		 *
		 * @param string $template The template name.
		 * @return mixed $template
		 */
		public function woocommerce_call_for_credit_form_template_path( $template ) {
			$template_name = 'call-for-credit-form.php';

			$template = $this->locate_template_for_smart_coupons( $template_name, $template );

			return $template;
		}

		/**
		 * Make product whose price is set as zero but is for purchasing credit, purchasable
		 *
		 * @param boolean    $purchasable Is purchasable.
		 * @param WC_Product $product The product.
		 * @return boolean   $purchasable
		 */
		public function make_product_purchasable( $purchasable, $product ) {
			try {
				if ( $this->is_wc_gte_30() ) {
					$product_id = ( is_object( $product ) && is_callable( array( $product, 'get_id' ) ) ) ? $product->get_id() : 0;
				} else {
					$product_id = ( ! empty( $product->id ) ) ? $product->id : 0;
				}
				$coupons = $this->get_coupon_titles( array( 'product_object' => $product ) );

				if ( ! empty( $coupons ) && $product instanceof WC_Product && $product->get_price() === '' && $this->is_coupon_amount_pick_from_product_price( $coupons ) && ! ( $product->get_price() > 0 ) ) {
					return true;
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $purchasable;
		}

		/**
		 * Remove price html for product which is selling any amount of storecredit
		 *
		 * @param string     $price Current price HTML.
		 * @param WC_Product $product The product object.
		 * @return string $price
		 */
		public function price_html_for_purchasing_credit( $price = null, $product = null ) {
			try {
				if ( $this->is_wc_gte_30() ) {
					$product_id = ( is_object( $product ) && is_callable( array( $product, 'get_id' ) ) ) ? $product->get_id() : 0;
				} else {
					$product_id = ( ! empty( $product->id ) ) ? $product->id : 0;
				}
				$coupons = $this->get_coupon_titles( array( 'product_object' => $product ) );

				$is_product            = is_a( $product, 'WC_Product' );
				$is_purchasable_credit = $this->is_coupon_amount_pick_from_product_price( $coupons );
				$product_price         = $product->get_price();

				if ( ! empty( $coupons ) && true === $is_product && true === $is_purchasable_credit && ( ! ( $product_price > 0 ) || empty( $product_price ) ) ) {
					return '';
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
				$price = '';
			}

			return $price;
		}

		/**
		 * Set price for store credit to be purchased before calculating total in cart
		 *
		 * @param WC_Cart $cart_object The cart object.
		 */
		public function override_price_before_calculate_totals( $cart_object ) {
			try {
				$credit_called = $this->get_session( 'credit_called' );

				foreach ( $cart_object->cart_contents as $key => $value ) {

					$product       = $value['data'];
					$credit_amount = ( ! empty( $value['credit_amount'] ) ) ? floatval( $value['credit_amount'] ) : 0;

					if ( $this->is_wc_gte_30() ) {
						$product_type  = ( is_object( $product ) && is_callable( array( $product, 'get_type' ) ) ) ? $product->get_type() : '';
						$product_id    = ( in_array( $product_type, array( 'variable', 'variable-subscription', 'variation', 'subscription_variation' ), true ) ) ? ( ( is_object( $product ) && is_callable( array( $product, 'get_parent_id' ) ) ) ? $product->get_parent_id() : 0 ) : ( ( is_object( $product ) && is_callable( array( $product, 'get_id' ) ) ) ? $product->get_id() : 0 );
						$product_price = ( is_object( $product ) && is_callable( array( $product, 'get_price' ) ) ) ? $product->get_price() : 0;
					} else {
						$product_id    = ( ! empty( $product->id ) ) ? $product->id : 0;
						$product_price = ( ! empty( $product->price ) ) ? $product->price : 0;
					}

					$coupons = $this->get_coupon_titles( array( 'product_object' => $product ) );

					if ( ! empty( $coupons ) && $this->is_coupon_amount_pick_from_product_price( $coupons ) && ! ( $product_price > 0 ) ) {

						$price                                = ( ! empty( $credit_called[ $key ] ) ) ? floatval( $credit_called[ $key ] ) : $credit_amount;
						$is_purchase_credit_is_a_gift_product = apply_filters( 'sc_is_purchase_credit_is_a_gift_product', isset( $value['wc_sc_product_source'] ) ? true : false );

						if ( $price <= 0 && ! $is_purchase_credit_is_a_gift_product ) {
							WC()->cart->set_quantity( $key, 0 );    // Remove product from cart if price is not found either in session or in product.
							continue;
						}

						$price = $this->read_price( $price, true );

						if ( $this->is_wc_gte_30() && is_callable( array( $cart_object->cart_contents[ $key ]['data'], 'set_price' ) ) ) {
							$cart_object->cart_contents[ $key ]['data']->set_price( $price );
						} else {
							$cart_object->cart_contents[ $key ]['data']->price = $price;
						}
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Override empty price of voucher product by 0 to avoid 'non numeric value' warning for product price being triggered on coupon validation.
		 *
		 * @param string     $price product price.
		 * @param WC_Product $product WooCommerce product.
		 * @return integer $price new product price
		 */
		public function override_voucher_product_empty_price( $price, $product ) {
			try {
				global $pagenow;
				// Skip non-front-end requests.
				if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || wp_is_rest_endpoint() || defined( 'REST_REQUEST' ) ) {
					if ( function_exists( 'get_current_screen' ) ) {
						$screen = get_current_screen();
						if ( ! empty( $screen->post_type ) && 'product' === $screen->post_type ) {
							return $price; // No need to run the following code when working with products.
						}
					}
					$get_post      = ( ! empty( $_GET['post'] ) ) ? wc_clean( wp_unslash( $_GET['post'] ) ) : '';            // phpcs:ignore
					$get_post_type = ( ! empty( $_GET['post_type'] ) ) ? wc_clean( wp_unslash( $_GET['post_type'] ) ) : '';  // phpcs:ignore
					if ( 'post.php' === $pagenow && ! empty( $get_post ) && 'product' === get_post_type( $get_post ) ) {
						return $price;  // No need to run the following code when working with products.
					}
					if ( 'post-new.php' === $pagenow && ! empty( $get_post_type ) && 'product' === $get_post_type ) {
						return $price;  // No need to run the following code when working with products.
					}
				}
				if ( ! doing_action( 'woocommerce_single_product_summary' ) ) {

					if ( $this->is_wc_gte_30() ) {
						$product_type = ( is_object( $product ) && is_callable( array( $product, 'get_type' ) ) ) ? $product->get_type() : '';
						$product_id   = ( in_array( $product_type, array( 'variable', 'variable-subscription', 'variation', 'subscription_variation' ), true ) ) ? ( ( is_object( $product ) && is_callable( array( $product, 'get_parent_id' ) ) ) ? $product->get_parent_id() : 0 ) : ( ( is_object( $product ) && is_callable( array( $product, 'get_id' ) ) ) ? $product->get_id() : 0 );
					} else {
						$product_id = ( ! empty( $product->id ) ) ? $product->id : 0;
					}

					$coupons = $this->get_coupon_titles( array( 'product_object' => $product ) );

					// Override product price only if product contains coupon and price is already an empty string.
					if ( ! empty( $coupons ) && '' === $price ) {
						$price = 0;
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
				$price = 0;
			}

			return $price;
		}

		/**
		 * Display store credit's value as cart item's price
		 *
		 * @param string $product_price The product price HTML.
		 * @param array  $cart_item Associative array of cart item.
		 * @param string $cart_item_key The cart item key.
		 * @return string product's price with currency symbol
		 */
		public function woocommerce_cart_item_price_html( $product_price, $cart_item, $cart_item_key ) {
			try {
				$gift_certificate = $this->get_session( 'credit_called' );

				if ( ! empty( $gift_certificate ) && isset( $gift_certificate[ $cart_item_key ] ) && ! empty( $gift_certificate[ $cart_item_key ] ) ) {
					$price = $gift_certificate[ $cart_item_key ];
					$price = $this->read_price( $price, true );
					// Hook for 3rd party plugin to modify value of the credit.
					$price = apply_filters(
						'wc_sc_credit_called_price_cart',
						$price,
						array(
							'source'        => $this,
							'cart_item_key' => $cart_item_key,
							'cart_item'     => $cart_item,
							'credit_called' => $gift_certificate,
						)
					);
					return wc_price( $price );
				} elseif ( ! empty( $cart_item['credit_amount'] ) ) {
					$price = $cart_item['credit_amount'];
					$price = $this->read_price( $price, true );
					// Hook for 3rd party plugin to modify value of the credit.
					$price = apply_filters(
						'wc_sc_credit_called_price_cart',
						$price,
						array(
							'source'        => $this,
							'cart_item_key' => $cart_item_key,
							'cart_item'     => $cart_item,
							'credit_called' => $gift_certificate,
						)
					);
					return wc_price( $price );
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $product_price;
		}

		/**
		 * Receiver Detail Form Styles And Scripts
		 */
		public function receiver_detail_form_styles_and_scripts() {
			try {
				global $pagenow;
				// Skip non-front-end requests.
				if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || wp_is_rest_endpoint() || defined( 'REST_REQUEST' ) ) {
					if ( function_exists( 'get_current_screen' ) ) {
						$screen = get_current_screen();
						if ( ! empty( $screen->post_type ) && 'product' === $screen->post_type ) {
							return; // No need to run the following code when working with products.
						}
					}
					$get_post      = ( ! empty( $_GET['post'] ) ) ? wc_clean( wp_unslash( $_GET['post'] ) ) : '';            // phpcs:ignore
					$get_post_type = ( ! empty( $_GET['post_type'] ) ) ? wc_clean( wp_unslash( $_GET['post_type'] ) ) : '';  // phpcs:ignore
					if ( 'post.php' === $pagenow && ! empty( $get_post ) && 'product' === get_post_type( $get_post ) ) {
						return;  // No need to run the following code when working with products.
					}
					if ( 'post-new.php' === $pagenow && ! empty( $get_post_type ) && 'product' === $get_post_type ) {
						return;  // No need to run the following code when working with products.
					}
				}
				if ( ! wp_script_is( 'jquery' ) ) {
					wp_enqueue_script( 'jquery' );
				}
				$deliver_coupon_option = apply_filters(
					'wc_sc_deliver_coupon',
					'now',
					array(
						'source'                => $this,
						'cart_contents'         => ( isset( WC()->cart->cart_contents ) && is_array( WC()->cart->cart_contents ) ) ? WC()->cart->cart_contents : array(),
						'schedule_store_credit' => get_option( 'smart_coupons_schedule_store_credit' ),
					)
				);
				?>
				<!-- WooCommerce Smart Coupons Styles And Scripts Start -->
				<style type="text/css" media="screen">

					.wc-sc-toggle-check-input {
						width: 0;
						height: 0;
						visibility: hidden;
					}

					.wc-sc-toggle-check-text {
						display: inline-block;
						position: relative;
						text-transform: uppercase;
						font-size: small;
						background: #71b02f;
						padding: 0 .8rem 0 1.5rem;
						border-radius: 1rem;
						color: #fff;
						cursor: pointer;
						transition: background-color 0.15s;
					}

					.wc-sc-toggle-check-text:after {
						content: ' ';
						display: block;
						background: #fff;
						width: 0.8rem;
						height: 0.8rem;
						border-radius: 0.8rem;
						position: absolute;
						left: 0.3rem;
						top: 0.25rem;
						transition: left 0.15s, margin-left 0.15s;
					}

					.wc-sc-toggle-check-text:before {
						content: '<?php echo esc_attr__( 'Now', 'woocommerce-smart-coupons' ); ?>';
					}

					.wc-sc-toggle-check-input:checked ~ .wc-sc-toggle-check-text {
						background: #96588a;
						padding-left: .5rem;
						padding-right: 1.4rem;
					}

					.wc-sc-toggle-check-input:checked ~ .wc-sc-toggle-check-text:before {
						content: '<?php echo esc_attr__( 'Later', 'woocommerce-smart-coupons' ); ?>';
					}

					.wc-sc-toggle-check-input:checked ~ .wc-sc-toggle-check-text:after {
						left: 100%;
						margin-left: -1.1rem;
					}

				</style>
				<script type="text/javascript">
					jQuery(function(){
						function is_multi_form() {
							var creditCount = jQuery('div#gift-certificate-receiver-form-multi div.form_table').length;

							if ( creditCount <= 1 ) {
								return false;
							} else {
								return true;
							}
						}

						function reload_coupon_receiver_details_form() {
							if ( jQuery('input#show_form').is(':checked') ) {
								jQuery('form.woocommerce-checkout').find('input#show_form').trigger('click');
							}
							if ( jQuery('input#hide_form').is(':checked') ) {
								jQuery('form.woocommerce-checkout').find('input#hide_form').trigger('click');
							}
							if ( jQuery('form.woocommerce-checkout').find('input[name=sc_send_to]:checked').val() === 'many' ) {
								jQuery('form.woocommerce-checkout').find('input[name=sc_send_to]:checked').trigger('change');
							}
							jQuery('form.woocommerce-checkout').find('input#wc_sc_schedule_gift_sending').trigger('change');
						}

						jQuery('form.woocommerce-checkout').on('click', 'input#show_form', function(){
							if ( is_multi_form() ) {
								jQuery('ul.single_multi_list').slideDown();
							}
							jQuery('div.gift-certificate-receiver-detail-form').slideDown();
							jQuery('.wc_sc_schedule_gift_sending_wrapper').addClass('show');
						});
						jQuery('form.woocommerce-checkout').on('click', 'input#hide_form', function(){
							if ( is_multi_form() ) {
								jQuery('ul.single_multi_list').slideUp();
							}
							jQuery('div.gift-certificate-receiver-detail-form').slideUp();
							jQuery('.wc_sc_schedule_gift_sending_wrapper').removeClass('show');
						});
						jQuery('form.woocommerce-checkout').on('change', 'input[name=sc_send_to]', function(){
							jQuery('div#gift-certificate-receiver-form-single').slideToggle(1);
							jQuery('div#gift-certificate-receiver-form-multi').slideToggle(1);
						});
						jQuery('form.woocommerce-checkout').on('change', 'input#wc_sc_schedule_gift_sending', function(){
							if( jQuery(this).is(':checked') ) {
								jQuery('.email_sending_date_time_wrapper').addClass('show');
							} else {
								jQuery('.email_sending_date_time_wrapper').removeClass('show');
							}
						});
					jQuery('form.woocommerce-checkout').on('change', 'input#wc_sc_schedule_gift_sending', function(){
						if ( jQuery(this).is(':checked') && false === jQuery('.gift_sending_date_time').hasClass('hasDatepicker') ) {
							setTimeout(function(){
								const datepickerOptions = <?php echo $this->get_datetimepicker_options_json(); //phpcs:ignore ?>;
								datepickerOptions.isRTL = (typeof wp !== 'undefined' && wp.i18n && wp.i18n.isRTL) ? wp.i18n.isRTL() : false;
								jQuery('input.gift_sending_date_time').datetimepicker(datepickerOptions);
							}, 10);
						}
					});

						var deliver_coupon_option = '<?php echo esc_html( $deliver_coupon_option ); ?>';

						if ( 'later' === deliver_coupon_option ){
							jQuery('form.woocommerce-checkout').find('.email_sending_date_time_wrapper').addClass('show');
							jQuery('form.woocommerce-checkout').find('input#wc_sc_schedule_gift_sending').prop('checked', true).trigger('change');
						}

						reload_coupon_receiver_details_form();
					});
				</script>
				<!-- WooCommerce Smart Coupons Styles And Scripts End -->
				<?php
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Function to display form for entering details of the gift certificate's receiver
		 */
		public function gift_certificate_receiver_detail_form() {
			try {
				global $total_coupon_amount;

				$is_show = apply_filters( 'is_show_gift_certificate_receiver_detail_form', true, array() );

				if ( ! $is_show ) {
					return;
				}

				if ( ! wp_style_is( 'smart-coupon' ) ) {
					wp_enqueue_style( 'smart-coupon' );
				}

				if ( ! wp_doing_ajax() ) {
					add_action( 'wp_footer', array( $this, 'receiver_detail_form_styles_and_scripts' ) );
				}

				$form_started = false;

				$all_discount_types = wc_get_coupon_types();

				$schedule_store_credit = get_option( 'smart_coupons_schedule_store_credit' );

				$coupon_receiver_details_session = $this->get_coupon_receiver_details_session();

				if ( ! is_null( $coupon_receiver_details_session ) ) {
					$is_gift                     = ( ! empty( $coupon_receiver_details_session['is_gift'] ) ) ? wc_clean( wp_unslash( $coupon_receiver_details_session['is_gift'] ) ) : '';
					$sc_send_to                  = ( ! empty( $coupon_receiver_details_session['sc_send_to'] ) ) ? wc_clean( wp_unslash( $coupon_receiver_details_session['sc_send_to'] ) ) : '';
					$wc_sc_schedule_gift_sending = ( ! empty( $coupon_receiver_details_session['wc_sc_schedule_gift_sending'] ) ) ? wc_clean( wp_unslash( $coupon_receiver_details_session['wc_sc_schedule_gift_sending'] ) ) : '';
					$gift_receiver_email         = ( ! empty( $coupon_receiver_details_session['gift_receiver_email'] ) ) ? wc_clean( wp_unslash( $coupon_receiver_details_session['gift_receiver_email'] ) ) : array();
					$gift_sending_date_time      = ( ! empty( $coupon_receiver_details_session['gift_sending_date_time'] ) ) ? wc_clean( wp_unslash( $coupon_receiver_details_session['gift_sending_date_time'] ) ) : array();
					$gift_sending_timestamp      = ( ! empty( $coupon_receiver_details_session['gift_sending_timestamp'] ) ) ? wc_clean( wp_unslash( $coupon_receiver_details_session['gift_sending_timestamp'] ) ) : array();
					$gift_receiver_message       = ( ! empty( $coupon_receiver_details_session['gift_receiver_message'] ) ) ? wc_clean( wp_unslash( $coupon_receiver_details_session['gift_receiver_message'] ) ) : array();
				} else {
					$is_gift                     = '';
					$sc_send_to                  = '';
					$wc_sc_schedule_gift_sending = '';
					$gift_receiver_email         = array();
					$gift_sending_date_time      = array();
					$gift_sending_timestamp      = array();
					$gift_receiver_message       = array();
				}

				$coupon_receiver_details_session = array(
					'is_gift'                     => $is_gift,
					'sc_send_to'                  => $sc_send_to,
					'wc_sc_schedule_gift_sending' => $wc_sc_schedule_gift_sending,
					'gift_receiver_email'         => $gift_receiver_email,
					'gift_sending_date_time'      => $gift_sending_date_time,
					'gift_sending_timestamp'      => $gift_sending_timestamp,
					'gift_receiver_message'       => $gift_receiver_message,
				);

				foreach ( WC()->cart->cart_contents as $product ) {

					if ( ! empty( $product['variation_id'] ) ) {
						$_product = wc_get_product( $product['variation_id'] );
					} elseif ( ! empty( $product['product_id'] ) ) {
						$_product = wc_get_product( $product['product_id'] );
					} else {
						continue;
					}

					$coupon_titles = $this->get_coupon_titles( array( 'product_object' => $_product ) );

					$price = $_product->get_price();

					if ( $coupon_titles ) {

						foreach ( $coupon_titles as $coupon_title ) {

							$coupon = new WC_Coupon( $coupon_title );
							if ( $this->is_wc_gte_30() ) {
								if ( ! is_object( $coupon ) || ! is_callable( array( $coupon, 'get_id' ) ) ) {
									continue;
								}
								$coupon_id = $coupon->get_id();
								if ( empty( $coupon_id ) ) {
									continue;
								}
								$discount_type = $coupon->get_discount_type();
							} else {
								$coupon_id     = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
								$discount_type = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
							}

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

							$pick_price_of_prod                              = ( $this->is_callable( $coupon, 'get_meta' ) ) ? $coupon->get_meta( 'is_pick_price_of_product' ) : get_post_meta( $coupon_id, 'is_pick_price_of_product', true );
							$smart_coupon_gift_certificate_form_page_text    = get_option( 'smart_coupon_gift_certificate_form_page_text' );
							$smart_coupon_gift_certificate_form_page_text    = ( ! empty( $smart_coupon_gift_certificate_form_page_text ) ) ? $smart_coupon_gift_certificate_form_page_text : __( 'Send Coupons to...', 'woocommerce-smart-coupons' );
							$smart_coupon_gift_certificate_form_details_text = get_option( 'smart_coupon_gift_certificate_form_details_text' );
							$smart_coupon_gift_certificate_form_details_text = ( ! empty( $smart_coupon_gift_certificate_form_details_text ) ) ? $smart_coupon_gift_certificate_form_details_text : '';     // Enter email address and optional message for Gift Card receiver.

							// MADE CHANGES IN THE CONDITION TO SHOW FORM.
							if ( array_key_exists( $discount_type, $all_discount_types ) || ( 'yes' === $pick_price_of_prod && '' === $price ) || ( 'yes' === $pick_price_of_prod && '' !== $price && $coupon_amount > 0 ) ) {

								if ( ! $form_started ) {
									$is_show_coupon_receiver_form = get_option( 'smart_coupons_display_coupon_receiver_details_form', 'yes' );
									if ( 'no' === $is_show_coupon_receiver_form ) {
										?>
										<div class="gift-certificate sc_info_box">
											<p><?php echo esc_html__( 'Your order contains coupons. You will receive them after completion of this order.', 'woocommerce-smart-coupons' ); ?></p>
										</div>
										<?php
									}
									?>
									<div class="gift-certificate sc_info_box" <?php echo ( 'no' === $is_show_coupon_receiver_form ) ? 'style="' . esc_attr( 'display: none;' ) . '"' : ''; ?>>
										<h3><?php echo esc_html( stripslashes( $smart_coupon_gift_certificate_form_page_text ) ); ?></h3>
											<?php if ( ! empty( $smart_coupon_gift_certificate_form_details_text ) ) { ?>
											<p><?php echo esc_html( stripslashes( $smart_coupon_gift_certificate_form_details_text ) ); ?></p>
											<?php } ?>
											<div class="gift-certificate-show-form">
												<p><?php echo esc_html__( 'Your order contains coupons. What would you like to do?', 'woocommerce-smart-coupons' ); ?></p>
												<ul class="show_hide_list" style="list-style-type: none;">
													<li><input type="radio" id="hide_form" name="is_gift" value="no" <?php checked( in_array( $is_gift, array( 'no', '' ), true ) ); ?> /> <label for="hide_form"><?php echo esc_html__( 'Send to me', 'woocommerce-smart-coupons' ); ?></label></li>
													<li>
													<input type="radio" id="show_form" name="is_gift" value="yes" <?php checked( $is_gift, 'yes' ); ?> /> <label for="show_form"><?php echo esc_html__( 'Gift to someone else', 'woocommerce-smart-coupons' ); ?></label>
													<ul class="single_multi_list" style="list-style-type: none;">
													<li><input type="radio" id="send_to_one" name="sc_send_to" value="one" <?php checked( in_array( $sc_send_to, array( 'one', '' ), true ) ); ?> /> <label for="send_to_one"><?php echo esc_html__( 'Send to one person', 'woocommerce-smart-coupons' ); ?></label></li>
													<li><input type="radio" id="send_to_many" name="sc_send_to" value="many" <?php checked( $sc_send_to, 'many' ); ?> /> <label for="send_to_many"><?php echo esc_html__( 'Send to different people', 'woocommerce-smart-coupons' ); ?></label></li>
													</ul>
													<?php if ( 'yes' === $schedule_store_credit ) { ?>
														<li class="wc_sc_schedule_gift_sending_wrapper">
															<?php echo esc_html__( 'Deliver coupon', 'woocommerce-smart-coupons' ); ?>
															<label class="wc-sc-toggle-check">
																<input type="checkbox" class="wc-sc-toggle-check-input" id="wc_sc_schedule_gift_sending" name="wc_sc_schedule_gift_sending" value="yes" <?php checked( $wc_sc_schedule_gift_sending, 'yes' ); ?> />
																<span class="wc-sc-toggle-check-text"></span>
															</label>
														</li>
													<?php } ?>
													</li>
												</ul>
											</div>
									<div class="gift-certificate-receiver-detail-form">
									<div class="clear"></div>
									<div id="gift-certificate-receiver-form-multi">
									<?php

									$form_started = true;

								}

								$this->add_text_field_for_email( $coupon, $product, $coupon_receiver_details_session );

							}
						}
					}
				}

				if ( $form_started ) {
					?>
					</div>
					<div id="gift-certificate-receiver-form-single">
						<div class="form_table">
							<div class="email_amount">
								<div class="amount"></div>
								<div class="email"><input class="gift_receiver_email" type="text" placeholder="<?php echo esc_attr__( 'Enter recipient e-mail address', 'woocommerce-smart-coupons' ); ?>..." name="gift_receiver_email[0][0]" value="<?php echo esc_attr( ( ! empty( $gift_receiver_email[0][0] ) ) ? $gift_receiver_email[0][0] : '' ); ?>" /></div>
							</div>
							<div class="email_sending_date_time_wrapper">
									<input class="gift_sending_date_time" type="text" placeholder="<?php echo esc_attr__( 'Pick a delivery date & time', 'woocommerce-smart-coupons' ); ?>..." name="gift_sending_date_time[0][0]" value="<?php echo esc_attr( ( ! empty( $gift_sending_date_time[0][0] ) ) ? $gift_sending_date_time[0][0] : '' ); ?>" autocomplete="off" style="position: relative; z-index: 99997;"/>
							</div>
							<div class="message_row">
								<div class="message"><textarea placeholder="<?php echo esc_attr__( 'Write a message', 'woocommerce-smart-coupons' ); ?>..." class="gift_receiver_message" name="gift_receiver_message[0][0]" cols="50" rows="5"><?php echo esc_html( ( ! empty( $gift_receiver_message[0][0] ) ) ? $gift_receiver_message[0][0] : '' ); ?></textarea></div>
							</div>
						</div>
					</div>
					</div></div>
					<?php
					do_action( 'wc_sc_gift_certificate_form_shown' );
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Function to add hooks based on conditions
		 */
		public function purchase_credit_hooks() {
			if ( $this->is_wc_gte_30() ) {
				add_action( 'woocommerce_new_order_item', array( $this, 'save_called_credit_details_in_order_item' ), 10, 3 );
			} else {
				add_action( 'woocommerce_add_order_item_meta', array( $this, 'save_called_credit_details_in_order_item_meta' ), 10, 2 );
			}
		}

		/**
		 * Display form to enter receiver's details on checkout page
		 *
		 * @param WC_Coupon $coupon The coupon object.
		 * @param array     $product The product object.
		 * @param array     $coupon_receiver_details_session Coupon receiver details from.
		 */
		public function add_text_field_for_email( $coupon = '', $product = '', $coupon_receiver_details_session = array() ) {
			global $total_coupon_amount;

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

			extract( $coupon_receiver_details_session ); // phpcs:ignore

			$sell_sc_at_less_price = get_option( 'smart_coupons_sell_store_credit_at_less_price', 'no' );

			$coupon_data = $this->get_coupon_meta_data( $coupon );

			if ( $this->is_wc_gte_30() ) {
				$coupon_id        = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_id' ) ) ) ? $coupon->get_id() : '';
				$coupon_code      = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_code' ) ) ) ? $coupon->get_code() : '';
				$product_price    = ( is_object( $product['data'] ) && is_callable( array( $product['data'], 'get_price' ) ) ) ? $product['data']->get_price() : 0;
				$is_free_shipping = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_free_shipping' ) ) ) ? ( ( $coupon->get_free_shipping() ) ? 'yes' : 'no' ) : '';
				$discount_type    = ( is_object( $coupon ) && is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : '';
			} else {
				$coupon_id        = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
				$coupon_code      = ( ! empty( $coupon->code ) ) ? $coupon->code : '';
				$product_price    = ( ! empty( $product['data']->price ) ) ? $product['data']->price : 0;
				$is_free_shipping = ( ! empty( $coupon->free_shipping ) ) ? $coupon->free_shipping : '';
				$discount_type    = ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '';
			}

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

			for ( $i = 0; $i < $product['quantity']; $i++ ) {

				if ( $this->is_coupon_amount_pick_from_product_price( array( $coupon_code ) ) ) {
					if ( 'yes' === $sell_sc_at_less_price ) {
						$_coupon_amount = ( is_object( $product['data'] ) && is_callable( array( $product['data'], 'get_regular_price' ) ) ) ? $product['data']->get_regular_price() : 0;
						if ( empty( $_coupon_amount ) && ! empty( $product_price ) ) {
							$_coupon_amount = $product_price;
						}
					} else {
						$_coupon_amount = $product_price;
					}
					if ( empty( $_coupon_amount ) && ! empty( $product['credit_amount'] ) ) {
						$_coupon_amount = (float) $product['credit_amount'];
					}
				} else {
					$_coupon_amount = $coupon_amount;
				}

				// NEWLY ADDED CONDITION TO NOT TO SHOW TEXTFIELD IF COUPON AMOUNT IS "0".
				// TODO: Free Gift Coupon: Due to coupon amount as zero, following condition is not showing multiple form to send coupon to different people.
				if ( '' !== $_coupon_amount || $_coupon_amount > 0 || $coupon_amount > 0 || 'yes' === $is_free_shipping ) {

					$total_coupon_amount += $_coupon_amount;

					$formatted_coupon_text   = '';
					$formatted_coupon_amount = 0;
					if ( ! empty( $_coupon_amount ) || ! empty( $coupon_amount ) ) {
						$formatted_coupon_amount = ( $coupon_amount <= 0 ) ? wc_price( $_coupon_amount ) : $coupon_data['coupon_amount'];
						$formatted_coupon_text  .= $coupon_data['coupon_type'];
						if ( 'yes' === $is_free_shipping ) {
							$formatted_coupon_text .= ' &amp; ';
						}
					}
					if ( 'yes' === $is_free_shipping ) {
						$formatted_coupon_text .= __( 'Free Shipping coupon', 'woocommerce-smart-coupons' );
					}
					if ( 'smart_coupon' !== $discount_type && strpos( $formatted_coupon_text, 'coupon' ) === false ) {
						$formatted_coupon_text .= ' ' . __( 'coupon', 'woocommerce-smart-coupons' );
					}
					?>
					<div class="form_table">
						<div class="email_amount">
							<?php /* translators: 1. Coupon type 2. Coupon amount */ ?>
							<div class="amount"><?php echo esc_html__( 'Send', 'woocommerce-smart-coupons' ) . ' ' . esc_html( $formatted_coupon_text ) . ' ' . esc_html__( 'of', 'woocommerce-smart-coupons' ) . ' ' . $formatted_coupon_amount; // phpcs:ignore ?></div>
							<div class="email"><input class="gift_receiver_email" type="text" placeholder="<?php echo esc_attr__( 'Enter recipient e-mail address', 'woocommerce-smart-coupons' ); ?>..." name="gift_receiver_email[<?php echo esc_attr( $coupon_id ); ?>][]" value="<?php echo esc_attr( ( ! empty( $gift_receiver_email[ $coupon_id ][ $i ] ) ) ? $gift_receiver_email[ $coupon_id ][ $i ] : '' ); ?>" /></div>
						</div>
						<div class="email_sending_date_time_wrapper">
							<div class="sending_date_time"></div>
							<div class="email">
								<input class="gift_sending_date_time" type="text" placeholder="<?php echo esc_attr__( 'Pick a delivery date & time', 'woocommerce-smart-coupons' ); ?>..." name="gift_sending_date_time[<?php echo esc_attr( $coupon_id ); ?>][]" value="<?php echo esc_attr( ( ! empty( $gift_sending_date_time[ $coupon_id ][ $i ] ) ) ? $gift_sending_date_time[ $coupon_id ][ $i ] : '' ); ?>" autocomplete="off" style="position: relative; z-index: 99997;"/>
							</div>
						</div>

						<div class="message_row">
							<div class="sc_message"><textarea placeholder="<?php echo esc_attr__( 'Write a message', 'woocommerce-smart-coupons' ); ?>..." class="gift_receiver_message" name="gift_receiver_message[<?php echo esc_attr( $coupon_id ); ?>][]" cols="50" rows="5"><?php echo esc_html( ( ! empty( $gift_receiver_message[ $coupon_id ][ $i ] ) ) ? $gift_receiver_message[ $coupon_id ][ $i ] : '' ); ?></textarea></div>
						</div>
					</div>
					<?php
				}
			}
		}

		/**
		 * Save called credit details in order via store api
		 *
		 * @param \WC_Order $order The order object.
		 */
		public function save_called_credit_details_in_order_via_store_api( $order = null ) {
			if ( is_a( $order, 'WC_Order' ) ) {
				$order_id = $this->is_callable( $order, 'get_id' ) ? $order->get_id() : 0;
				$this->save_called_credit_details_in_order( $order_id );
			}
		}

		/**
		 * Save entered credit value by customer in order for further processing
		 *
		 * @param int   $order_id The order id.
		 * @param array $posted Associative array of posted data.
		 */
		public function save_called_credit_details_in_order( $order_id = 0, $posted = array() ) {
			try {
				$order       = wc_get_order( $order_id );
				$order_items = $order->get_items();

				$sc_called_credit = array();
				$update           = false;

				$prices_include_tax = ( get_option( 'woocommerce_prices_include_tax' ) === 'yes' ) ? true : false;

				foreach ( $order_items as $item_id => $order_item ) {

					$item_sc_called_credit = $this->get_meta( $order_item, 'sc_called_credit', true );

					if ( ! empty( $item_sc_called_credit ) ) {

						$product = ( is_object( $order_item ) && is_callable( array( $order_item, 'get_product' ) ) ) ? $order_item->get_product() : $order->get_product_from_item( $order_item );

						if ( ! is_object( $product ) ) {
							continue;
						}

						if ( $this->is_wc_gte_30() ) {
							$product_type = ( is_object( $product ) && is_callable( array( $product, 'get_type' ) ) ) ? $product->get_type() : '';
							$product_id   = ( in_array( $product_type, array( 'variable', 'variable-subscription', 'variation', 'subscription_variation' ), true ) ) ? ( ( is_object( $product ) && is_callable( array( $product, 'get_parent_id' ) ) ) ? $product->get_parent_id() : 0 ) : ( ( is_object( $product ) && is_callable( array( $product, 'get_id' ) ) ) ? $product->get_id() : 0 );
							$item_qty     = ( is_object( $order_item ) && is_callable( array( $order_item, 'get_quantity' ) ) ) ? $order_item->get_quantity() : 1;
							$item_tax     = ( is_object( $order_item ) && is_callable( array( $order_item, 'get_subtotal_tax' ) ) ) ? $order_item->get_subtotal_tax() : 0;
						} else {
							$product_id = ( ! empty( $product->id ) ) ? $product->id : 0;
							$item_qty   = ( ! empty( $order_item['qty'] ) ) ? $order_item['qty'] : 1;
							$item_tax   = ( ! empty( $order_item['line_subtotal_tax'] ) ) ? $order_item['line_subtotal_tax'] : 0;
						}

						if ( true === $prices_include_tax && ! $this->is_generated_store_credit_includes_tax() ) {
							$item_total = $item_sc_called_credit - $item_tax;
						} elseif ( false === $prices_include_tax && $this->is_generated_store_credit_includes_tax() ) {
							$item_total = $item_sc_called_credit + $item_tax;
						} else {
							$item_total = $item_sc_called_credit;
						}

						if ( ! empty( $item_qty ) ) {
							$qty = $item_qty;
						} else {
							$qty = 1;
						}

						$coupon_titles = $this->get_coupon_titles( array( 'product_object' => $product ) );

						if ( $coupon_titles ) {

							foreach ( $coupon_titles as $coupon_title ) {

								$coupon = new WC_Coupon( $coupon_title );

								if ( $this->is_wc_gte_30() ) {
									if ( ! is_object( $coupon ) || ! is_callable( array( $coupon, 'get_id' ) ) ) {
										continue;
									}
									$coupon_id = $coupon->get_id();
									if ( empty( $coupon_id ) ) {
										continue;
									}
								} else {
									$coupon_id = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
								}

								if ( $this->is_coupon_amount_pick_from_product_price( array( $coupon_title ) ) ) {
									$products_price               = ( ! $prices_include_tax ) ? $item_total : $item_total + $item_tax;
									$amount                       = $products_price / $qty;
									$sc_called_credit[ $item_id ] = wc_round_discount( $amount, 2 );
									$update                       = true;
								}
							}
						}

						$this->delete_order_item_meta( $item_id, 'sc_called_credit' );
					}
				}
				if ( $update ) {
					$this->update_post_meta( $order_id, 'sc_called_credit_details', $sc_called_credit, true, $order );
				}

				$this->maybe_clear_credit_called_session();
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Save entered credit value by customer in order item meta
		 *
		 * @param int                 $item_id The order item id.
		 * @param array|WC_Order_Item $values Associative array containing item's details.
		 */
		public function save_called_credit_details_in_order_item_meta( $item_id = 0, $values = array() ) {
			try {
				if ( empty( $item_id ) || empty( $values ) ) {
					return;
				}
				$sell_sc_at_less_price = get_option( 'smart_coupons_sell_store_credit_at_less_price', 'no' );
				if ( $this->is_wc_gte_30() ) {
					if ( ! $values instanceof WC_Order_Item_Product ) {
						return;
					}
					$product = $values->get_product();
					if ( ! is_object( $product ) || ! is_a( $product, 'WC_Product' ) ) {
						return;
					}
					$product_type = ( is_object( $product ) && is_callable( array( $product, 'get_type' ) ) ) ? $product->get_type() : '';
					$product_id   = ( in_array( $product_type, array( 'variable', 'variable-subscription', 'variation', 'subscription_variation' ), true ) ) ? ( ( is_object( $product ) && is_callable( array( $product, 'get_parent_id' ) ) ) ? $product->get_parent_id() : 0 ) : ( ( is_object( $product ) && is_callable( array( $product, 'get_id' ) ) ) ? $product->get_id() : 0 );
					$qty          = ( is_callable( array( $values, 'get_quantity' ) ) ) ? $values->get_quantity() : 1;
					$qty          = ( ! empty( $qty ) ) ? absint( $qty ) : 1;

					// Check if selling store credit at less price is enabled.
					if ( 'yes' === $sell_sc_at_less_price ) {
						// For gift certificate of any amount.
						if ( isset( $values->legacy_values['credit_amount'] ) && ! empty( $values->legacy_values['credit_amount'] ) ) {
							$order_id      = ( ! empty( $item_id ) ) ? wc_get_order_id_by_order_item_id( $item_id ) : 0;
							$order         = ( ! empty( $order_id ) ) ? wc_get_order( $order_id ) : null;
							$credit_amount = $this->read_price( $values->legacy_values['credit_amount'], true, $order );
							$product_price = floatval( $credit_amount ) * $qty;
						} else {
							// For gift certificate of fixed price.
							$product_price = ( is_callable( array( $product, 'get_regular_price' ) ) ) ? floatval( $product->get_regular_price() ) * $qty : 0;
						}
					} else {
						$subtotal      = ( is_callable( array( $values, 'get_subtotal' ) ) ) ? $values->get_subtotal() : 0;
						$product_price = $subtotal;
					}
					if ( wp_doing_ajax() && defined( 'WP_ADMIN' ) && true === WP_ADMIN ) {
						$action   = ( ! empty( $_POST['action'] ) ) ? wc_clean( wp_unslash( $_POST['action'] ) ) : ''; // phpcs:ignore
						$order_id = ( ! empty( $_POST['order_id'] ) ) ? absint( $_POST['order_id'] ) : 0;
						if ( 'woocommerce_add_order_item' === $action && check_ajax_referer( 'order-item', 'security' ) && ! empty( $order_id ) ) {
							$product_price = $product_price / $qty;
						}
					}
				} else {
					if ( empty( $values['data'] ) ) {
						return;
					}
					$product       = $values['data'];
					$product_id    = ( ! empty( $values['product_id'] ) ) ? $values['product_id'] : 0;
					$product_price = ( ! empty( $values['data']->price ) ) ? $values['data']->price : 0;
				}

				if ( empty( $product_id ) ) {
					return;
				}

				$coupon_titles = $this->get_coupon_titles( array( 'product_object' => $product ) );

				if ( $this->is_coupon_amount_pick_from_product_price( $coupon_titles ) && $product_price > 0 ) {
					$this->add_order_item_meta( $item_id, 'sc_called_credit', $product_price, true );
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Save entered credit value by customer in order item
		 *
		 * @param int   $item_id The order item id.
		 * @param array $values Associative array containing item's details.
		 * @param int   $order_id The order id.
		 */
		public function save_called_credit_details_in_order_item( $item_id = 0, $values = array(), $order_id = 0 ) {

			$this->save_called_credit_details_in_order_item_meta( $item_id, $values );
		}

		/**
		 * Save entered credit value by customer in order for PayPal Express Checkout
		 *
		 * @param WC_Order $order The order object.
		 */
		public function ppe_save_called_credit_details_in_order( $order ) {
			if ( $this->is_wc_gte_30() ) {
				$order_id = ( is_object( $order ) && is_callable( array( $order, 'get_id' ) ) ) ? $order->get_id() : 0;
			} else {
				$order_id = ( ! empty( $order->id ) ) ? $order->id : 0;
			}
			$this->save_called_credit_details_in_order( $order_id, null );
		}

		/**
		 * Save entered credit value by customer in cart item data
		 *
		 * This function is only for simple products.
		 *
		 * @param array $cart_item_data The cart item data.
		 * @param int   $product_id The product id.
		 * @param int   $variation_id The variation id.
		 * @return array $cart_item_data
		 */
		public function call_for_credit_cart_item_data( $cart_item_data = array(), $product_id = '', $variation_id = '' ) {
			try {
				if ( ! empty( $variation_id ) && $variation_id > 0 || empty( $product_id ) ) {
					return $cart_item_data;
				}

				$_product = wc_get_product( $product_id );

				$coupons = ( $this->is_callable( $_product, 'get_meta' ) ) ? $_product->get_meta( '_coupon_title' ) : get_post_meta( $product_id, '_coupon_title', true );

				if ( ! empty( $coupons ) && $this->is_coupon_amount_pick_from_product_price( $coupons ) && ! ( $_product->get_price() > 0 ) ) {
					$request_credit_called           = ( ! empty( $_REQUEST['credit_called'] ) ) ? wc_clean( wp_unslash( $_REQUEST['credit_called'] ) ) : array(); // phpcs:ignore
					$request_add_to_cart             = ( ! empty( $_REQUEST['add-to-cart'] ) ) ? wc_clean( wp_unslash( $_REQUEST['add-to-cart'] ) ) : 0; // phpcs:ignore
					$request_product_id              = ( ! empty( $_REQUEST['product_id'] ) ) ? absint( $_REQUEST['product_id'] ) : 0; // phpcs:ignore
					$request_add_to_cart             = ! empty( $request_product_id ) ? $request_product_id : $request_add_to_cart;
					$product_id                      = apply_filters(
						'wc_sc_call_for_credit_product_id',
						$request_add_to_cart,
						array(
							'cart_item_data' => $cart_item_data,
							'product_id'     => $product_id,
							'variation_id'   => $variation_id,
							'source'         => $this,
						)
					);
					$cart_item_data['credit_amount'] = ( ! empty( $request_credit_called ) && ! empty( $product_id ) && ! empty( $request_credit_called[ $product_id ] ) ) ? $this->write_price( $request_credit_called[ $product_id ], true ) : 0;
					return $cart_item_data;
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}

			return $cart_item_data;
		}

		/**
		 * Save entered credit value by customer in session
		 *
		 * This function is only for simple products.
		 *
		 * @param string $cart_item_key The cart item key.
		 * @param int    $product_id The product id.
		 * @param int    $quantity The product quantity.
		 * @param int    $variation_id The variation id.
		 * @param array  $variation The variation data.
		 * @param array  $cart_item_data The cart item data.
		 */
		public function save_called_credit_in_session( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
			try {
				if ( ! empty( $variation_id ) && $variation_id > 0 ) {
					return;
				}
				if ( ! isset( $cart_item_data['credit_amount'] ) || empty( $cart_item_data['credit_amount'] ) ) {
					return;
				}

				$_product = wc_get_product( $product_id );

				$coupons = ( $this->is_callable( $_product, 'get_meta' ) ) ? $_product->get_meta( '_coupon_title' ) : get_post_meta( $product_id, '_coupon_title', true );

				if ( ! empty( $coupons ) && $this->is_coupon_amount_pick_from_product_price( $coupons ) && ! ( $_product->get_price() > 0 ) ) {
					$credit_called = $this->get_session( 'credit_called' );
					if ( empty( $credit_called ) || ! is_array( $credit_called ) ) {
						$credit_called = array();
					}
					$credit_called[ $cart_item_key ] = $cart_item_data['credit_amount'];
					$this->set_session( 'credit_called', $credit_called );
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Enqueue required styles/scripts for store credit frontend form
		 */
		public function enqueue_styles_scripts() {
			// Return if gift certificate form is not shown.
			if ( ! did_action( 'wc_sc_gift_certificate_form_shown' ) ) {
				return;
			}

			$this->enqueue_timepicker();

			?>
			<script type="text/javascript">
				jQuery(function(){
					if ( typeof wc_sc_ajax_save_coupon_receiver_details_in_session === 'undefined' ) {
						function wc_sc_ajax_save_coupon_receiver_details_in_session(){
							jQuery.ajax({
								url: '<?php echo esc_url( is_callable( array( 'WC_AJAX', 'get_endpoint' ) ) ? WC_AJAX::get_endpoint( 'wc_sc_save_coupon_receiver_details' ) : '/?wc-ajax=wc_sc_save_coupon_receiver_details' ); ?>',
								type: 'POST',
								dataType: 'json',
								data: {
									security: '<?php echo esc_html( wp_create_nonce( 'wc-sc-save-coupon-receiver-details' ) ); ?>',
									data: jQuery( 'form.checkout' ).serialize()
								},
								success: function( response ) {
									if ( 'yes' !== response.success ) {
										console.log(
											'<?php echo esc_js( _x( 'Failed to update coupon receiver details in session.', 'Error message when AJAX fails to update coupon receiver details', 'woocommerce-smart-coupons' ) ); ?>'
										);
									}
								}
							});
						}
					}
					jQuery('body').on('change', 'input[name="payment_method"]', wc_sc_ajax_save_coupon_receiver_details_in_session);
					jQuery('body').on('focusout', 'div.sc_info_box' , wc_sc_ajax_save_coupon_receiver_details_in_session);
				});
			</script>
			<?php
		}

		/**
		 * Add timepicker
		 */
		public function enqueue_timepicker() {
			if ( is_callable( 'WC_Smart_Coupons::get_smart_coupons_plugin_data' ) ) {
				$plugin_data = WC_Smart_Coupons::get_smart_coupons_plugin_data();
				$version     = $plugin_data['Version'];
			} else {
				$version = '';
			}

			$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';

			if ( ! wp_style_is( 'jquery-ui-style', 'registered' ) ) {
				wp_register_style( 'jquery-ui-style', WC()->plugin_url() . '/assets/css/jquery-ui/jquery-ui' . $suffix . '.css', array(), WC()->version );
			}

			if ( ! wp_style_is( 'jquery-ui-timepicker', 'registered' ) ) {
				wp_register_style( 'jquery-ui-timepicker', untrailingslashit( plugins_url( '/', WC_SC_PLUGIN_FILE ) ) . '/assets/css/jquery-ui-timepicker-addon' . $suffix . '.css', array( 'jquery-ui-style' ), $version );
			}

			if ( ! wp_style_is( 'jquery-ui-timepicker' ) ) {
				wp_enqueue_style( 'jquery-ui-timepicker' );
			}

			if ( ! wp_script_is( 'jquery-ui-timepicker', 'registered' ) ) {
				wp_register_script( 'jquery-ui-timepicker', untrailingslashit( plugins_url( '/', WC_SC_PLUGIN_FILE ) ) . '/assets/js/jquery-ui-timepicker-addon' . $suffix . '.js', array( 'jquery', 'jquery-ui-datepicker', 'jquery-ui-slider', 'wp-i18n' ), $version, true );
			}

			if ( ! wp_script_is( 'jquery-ui-timepicker' ) ) {
				wp_enqueue_script( 'jquery-ui-timepicker' );
			}
		}

		/**
		 * Clear session variable credit_called (if set) when cart is empty
		 */
		public function maybe_clear_credit_called_session() {
			if ( WC()->session->__isset( 'credit_called' ) ) {
				WC()->session->__unset( 'credit_called' );
			}
		}

		/**
		 * Validate checkout based on whether delivery time is required or not
		 *
		 * @param array    $fields checkout fields.
		 * @param WP_Error $errors WP Error Object.
		 * @return void
		 */
		public function maybe_required_coupon_delivery_date_time( $fields = array(), $errors = object ) {
			try {
				$nonce_value = ( ! empty( $_POST['woocommerce-process-checkout-nonce'] ) ) ? wc_clean( wp_unslash( $_POST['woocommerce-process-checkout-nonce'] ) ) : ''; // phpcs:ignore
				if ( ! wp_verify_nonce( $nonce_value, 'woocommerce-process_checkout' ) ) {
					return;
				}

				global $store_credit_label;

				$is_schedule_gift_sending = ( ! empty( $_POST['wc_sc_schedule_gift_sending'] ) ) ? wc_clean( wp_unslash( $_POST['wc_sc_schedule_gift_sending'] ) ) : '';                                             // phpcs:ignore
				$request_gift_sending_date_time = ( isset( $_REQUEST['gift_sending_date_time'] ) ) ? wc_clean( wp_unslash( $_REQUEST['gift_sending_date_time'] ) ) : array(); // phpcs:ignore
				$gift_sending_timestamp         = array();
				if ( ! empty( $request_gift_sending_date_time ) ) {
					$gift_sending_timestamp = $this->convert_gift_sending_date_time_to_timestamps( $request_gift_sending_date_time );
				}

				$send_to                  = ( ! empty( $_POST['sc_send_to'] ) ) ? wc_clean( wp_unslash( $_POST['sc_send_to'] ) ) : '';                                                                               // phpcs:ignore
				$is_gift                  = ( ! empty( $_POST['is_gift'] ) ) ? wc_clean( wp_unslash( $_POST['is_gift'] ) ) : '';                                                                                     // phpcs:ignore

				if ( 'yes' === $is_gift && 'yes' === $is_schedule_gift_sending ) {
					$is_date_available = true;
					if ( is_array( $gift_sending_timestamp ) && ! empty( $gift_sending_timestamp ) ) {
						if ( 'many' === $send_to ) {
							foreach ( $gift_sending_timestamp as $coupon_id => $timestamp ) {
								if ( 0 === absint( $coupon_id ) ) {
									continue;
								}
								$filtered = array_filter(
									$timestamp,
									function ( $value ) {
										return ! empty( $value );
									}
								);
								if ( count( $filtered ) !== count( $timestamp ) ) {
									$is_date_available = false;
									break;
								}
							}
						} elseif ( 'one' === $send_to ) {
							if ( empty( $gift_sending_timestamp[0][0] ) ) {
								$is_date_available = false;
							}
						}
					}
					if ( false === $is_date_available ) {
						if ( is_object( $errors ) && is_callable( array( $errors, 'add' ) ) ) {
							/* translators: %s: field name */
							$errors->add( 'validation', __( 'Coupon delivery date and time is a required field.', 'woocommerce-smart-coupons' ) );
						}
					}
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Save coupon receiver details in session
		 *
		 * @param array    $fields checkout fields.
		 * @param WP_Error $errors WP Error Object.
		 */
		public function save_coupon_receiver_details_in_session( $fields = array(), $errors = object ) {
			$nonce_value = ( ! empty( $_POST['woocommerce-process-checkout-nonce'] ) ) ? wc_clean( wp_unslash( $_POST['woocommerce-process-checkout-nonce'] ) ) : ''; // phpcs:ignore
			if ( ! wp_verify_nonce( $nonce_value, 'woocommerce-process_checkout' ) ) {
				return;
			}
			$posted_data = array_map( 'wp_unslash', $_POST ); // phpcs:ignore
			$posted_data = wc_clean( $posted_data ); // phpcs:ignore
			$this->set_coupon_receiver_details_session( $posted_data );
		}

		/**
		 * Set coupon receiver details in session variable
		 *
		 * @param array $posted_data The posted data.
		 */
		public function set_coupon_receiver_details_session( $posted_data = array() ) {
			try {
				if ( is_callable( 'WC' ) && is_object( WC() ) && is_object( WC()->session ) && is_callable( array( WC()->session, 'set' ) ) ) {
					$keys_to_copy            = array( 'is_gift', 'sc_send_to', 'wc_sc_schedule_gift_sending', 'gift_receiver_email', 'gift_sending_date_time', 'gift_sending_timestamp', 'gift_receiver_message' );
					$coupon_receiver_details = array();
					foreach ( $keys_to_copy as $key ) {
						if ( isset( $posted_data[ $key ] ) ) {
							$coupon_receiver_details[ $key ] = $posted_data[ $key ];
						}
					}
					if ( isset( $coupon_receiver_details['gift_sending_date_time'] ) ) {
						$coupon_receiver_details['gift_sending_timestamp'] = $this->convert_gift_sending_date_time_to_timestamps( $coupon_receiver_details['gift_sending_date_time'] );
					}
					$coupon_receiver_details = apply_filters(
						'wc_sc_before_set_coupon_receiver_details_session',
						$coupon_receiver_details,
						array(
							'source'      => $this,
							'posted_data' => $posted_data,
						)
					);

					WC()->session->set( 'wc_sc_coupon_receiver_details_session', ! empty( $coupon_receiver_details ) ? $coupon_receiver_details : null );
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Get coupon receiver details from session variable
		 */
		public function get_coupon_receiver_details_session() {
			if ( is_callable( 'WC' ) && is_object( WC() ) && is_object( WC()->session ) && is_callable( array( WC()->session, 'get' ) ) ) {
				return WC()->session->get( 'wc_sc_coupon_receiver_details_session' );
			}

			return null;
		}

		/**
		 * Function to cleanup order item meta if not required
		 *
		 * @param integer $order_id The order id.
		 */
		public function cleanup_order_item_meta( $order_id = 0 ) {
			if ( empty( $order_id ) ) {
				return;
			}

			$order       = wc_get_order( $order_id );
			$order_items = ( is_object( $order ) && is_callable( array( $order, 'get_items' ) ) ) ? $order->get_items() : array();

			foreach ( $order_items as $item_id => $order_item ) {
				$this->delete_order_item_meta( $item_id, 'sc_called_credit' );
			}
		}

		/**
		 * Save coupon receiver details in session during update order review
		 *
		 * @param array $fragments The fragments.
		 * @return array
		 */
		public function update_order_review_fragments( $fragments = array() ) {
			if ( ! empty( $_POST['post_data'] ) ) { // phpcs:ignore
				wp_parse_str( $_POST['post_data'], $posted_data ); // phpcs:ignore
				$this->set_coupon_receiver_details_session( $posted_data );
			}
			return $fragments;
		}

		/**
		 * Save coupon receiver detail via AJAX
		 */
		public function ajax_save_coupon_receiver_details() {
			try {
				check_ajax_referer( 'wc-sc-save-coupon-receiver-details', 'security' );

				wp_parse_str( wc_clean( wp_unslash( urldecode_deep( $_POST['data'] ) ) ), $posted_data ); // phpcs:ignore
				$this->set_coupon_receiver_details_session( $posted_data );

				wp_send_json( array( 'success' => 'yes' ) );
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
				wp_send_json( array( 'message' => __( 'Failed to save coupon receiver details.', 'woocommerce-smart-coupons' ) ) );
			}
		}

		/**
		 * Check & clear coupon receiver details from session when cart is emptied (e.g. after creation of order)
		 */
		public function maybe_clear_coupon_receiver_details_session() {
			$coupon_receiver_details_session = $this->get_coupon_receiver_details_session();
			if ( ! is_null( $coupon_receiver_details_session ) ) {
				WC()->session->set( 'wc_sc_coupon_receiver_details_session', null );
			}
		}

		/**
		 * Convert WordPress date/time format to jQuery Timepicker format.
		 *
		 * @param string $wp_format WordPress date or time format.
		 * @return string string jQuery Timepicker compatible format.
		 */
		public static function php_to_jquery_date_or_time_format( $wp_format ) {
			$replacements = array(
				// Date.
				'd' => 'dd', // Day with leading zero (01–31).
				'j' => 'd',  // Day without leading zero (1–31).
				'D' => 'D',  // Short weekday (Mon–Sun).
				'l' => 'DD', // Full weekday (Monday–Sunday).
				'm' => 'mm', // Month with leading zero (01–12).
				'n' => 'm',  // Month without leading zero (1–12).
				'M' => 'M',  // Short month (Jan–Dec).
				'F' => 'MM', // Full month (January–December).
				'Y' => 'yy', // Full year (e.g., 2025).
				'y' => 'y',  // Short year (e.g., 25).

				// Time.
				'g' => 'h',  // 12-hour format without leading zero (1–12).
				'h' => 'hh', // 12-hour format with leading zero (01–12).
				'G' => 'H',  // 24-hour format without leading zero (0–23).
				'H' => 'HH', // 24-hour format with leading zero (00–23).
				'i' => 'mm', // Minutes with leading zero (00–59).
				'a' => 'tt', // am/pm.
				'A' => 'TT', // AM/PM.
			);

			return strtr( $wp_format, $replacements );
		}

		/**
		 * Get jQuery UI datetimepicker options array.
		 *
		 * @return array Datetimepicker options array.
		 */
		public function get_datetimepicker_options() {
			global $wp_locale;

			return array(
				'dateFormat'      => self::php_to_jquery_date_or_time_format( get_option( 'date_format' ) ),
				'minDate'         => 0,
				'inline'          => true,
				'changeMonth'     => true,
				'changeYear'      => true,
				'timeInput'       => true,
				'currentText'     => _x( 'Now', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'closeText'       => _x( 'Done', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'monthNames'      => array(
					$wp_locale->month['01'],
					$wp_locale->month['02'],
					$wp_locale->month['03'],
					$wp_locale->month['04'],
					$wp_locale->month['05'],
					$wp_locale->month['06'],
					$wp_locale->month['07'],
					$wp_locale->month['08'],
					$wp_locale->month['09'],
					$wp_locale->month['10'],
					$wp_locale->month['11'],
					$wp_locale->month['12'],
				),
				'monthNamesShort' => array(
					$wp_locale->month_abbrev[ $wp_locale->month['01'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['02'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['03'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['04'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['05'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['06'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['07'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['08'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['09'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['10'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['11'] ],
					$wp_locale->month_abbrev[ $wp_locale->month['12'] ],
				),
				'dayNames'        => array(
					$wp_locale->weekday[0],
					$wp_locale->weekday[1],
					$wp_locale->weekday[2],
					$wp_locale->weekday[3],
					$wp_locale->weekday[4],
					$wp_locale->weekday[5],
					$wp_locale->weekday[6],
				),
				'dayNamesShort'   => array(
					$wp_locale->weekday_abbrev[ $wp_locale->weekday[0] ],
					$wp_locale->weekday_abbrev[ $wp_locale->weekday[1] ],
					$wp_locale->weekday_abbrev[ $wp_locale->weekday[2] ],
					$wp_locale->weekday_abbrev[ $wp_locale->weekday[3] ],
					$wp_locale->weekday_abbrev[ $wp_locale->weekday[4] ],
					$wp_locale->weekday_abbrev[ $wp_locale->weekday[5] ],
					$wp_locale->weekday_abbrev[ $wp_locale->weekday[6] ],
				),
				'dayNamesMin'     => array(
					$wp_locale->weekday_initial[ $wp_locale->weekday[0] ],
					$wp_locale->weekday_initial[ $wp_locale->weekday[1] ],
					$wp_locale->weekday_initial[ $wp_locale->weekday[2] ],
					$wp_locale->weekday_initial[ $wp_locale->weekday[3] ],
					$wp_locale->weekday_initial[ $wp_locale->weekday[4] ],
					$wp_locale->weekday_initial[ $wp_locale->weekday[5] ],
					$wp_locale->weekday_initial[ $wp_locale->weekday[6] ],
				),
				'amNames'         => array(
					$wp_locale->meridiem['AM'],
					$wp_locale->meridiem['am'],
				),
				'pmNames'         => array(
					$wp_locale->meridiem['PM'],
					$wp_locale->meridiem['pm'],
				),
				'timeFormat'      => self::php_to_jquery_date_or_time_format( get_option( 'time_format' ) ),
				'timeSuffix'      => '',
				'timeOnlyTitle'   => _x( 'Choose Time', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'timeText'        => _x( 'Time', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'hourText'        => _x( 'Hour', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'minuteText'      => _x( 'Minute', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'secondText'      => _x( 'Second', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'millisecText'    => _x( 'Millisecond', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'microsecText'    => _x( 'Microsecond', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'timezoneText'    => _x( 'Time Zone', 'Timepicker on the frontend side', 'woocommerce-smart-coupons' ),
				'isRTL'           => false, // Set dynamically in JavaScript.
			);
		}

		/**
		 * Get jQuery UI datetimepicker options as JSON string.
		 *
		 * @return string Escaped JSON string of datetimepicker options.
		 */
		public function get_datetimepicker_options_json() {
			$options          = $this->get_datetimepicker_options();
			$options['isRTL'] = false; // Will be set dynamically in JavaScript.
			return wp_json_encode( $options );
		}

		/**
		 * Enqueue scripts and styles for product page gift form.
		 *
		 * @since 9.64.0
		 * @return void
		 */
		public function enqueue_product_page_gift_form_assets() {
			// Only enqueue on single product pages.
			if ( ! is_product() ) {
				return;
			}

			// Check if coupon receiver form is enabled (EARLY EXIT).
			$is_show_coupon_receiver_form = get_option( 'smart_coupons_display_coupon_receiver_details_form', 'yes' );
			if ( 'no' === $is_show_coupon_receiver_form ) {
				return; // Don't load assets if form is disabled.
			}

			global $product;

			/**
			 * Filters whether to show the gift form on the product page.
			 *
			 * @since 9.64.0
			 * @hook wc_sc_show_product_page_gift_form
			 *
			 * @param bool        $show      Whether to show the product page gift form. Default true.
			 * @param array       $args      Additional arguments.
			 * @param WC_Product  $product   Product object.
			 * @param object      $source    Source object (this class instance).
			 *
			 * @return bool True to show the form, false to hide it.
			 */
			$is_show_product_page_form = apply_filters(
				'wc_sc_show_product_page_gift_form',
				true,
				array(
					'product' => $product,
					'source'  => $this,
				)
			);
			if ( ! $is_show_product_page_form ) {
				return; // Don't load assets if form is filtered out.
			}

			// use minified version in production, normal for debug.
			$suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';

			// Enqueue product page gift form styles.
			wp_enqueue_style(
				'wc-sc-product-page-gift-form',
				WC_SC_PLUGIN_URL . 'assets/css/product-page-gift-form' . $suffix . '.css',
				array(),
				$this->get_version()
			);

			// Enqueue JavaScript (use minified version in production, normal for debug).
			wp_enqueue_script(
				'wc-sc-product-page-gift-form',
				WC_SC_PLUGIN_URL . 'assets/js/product-page-gift-form' . $suffix . '.js',
				array( 'jquery' ),
				$this->get_version(),
				true
			);

			// Localize script with PHP data.
			$ajax_url   = admin_url( 'admin-ajax.php' );
			$ajax_nonce = wp_create_nonce( 'wc-sc-save-product-page-coupon-receiver-details' );

			// Get datepicker options.
			$datepicker_options          = $this->get_datetimepicker_options();
			$datepicker_options['isRTL'] = false; // Will be set dynamically in JavaScript.

			// Get translatable strings.
			$i18n = array(
				'send'                 => _x( 'Send', 'Gift form coupon label prefix', 'woocommerce-smart-coupons' ),
				'of'                   => _x( 'of', 'Gift form coupon label connector', 'woocommerce-smart-coupons' ),
				'enterRecipientEmail'  => _x( 'Enter recipient e-mail address', 'Product page gift form', 'woocommerce-smart-coupons' ),
				'writeMessage'         => _x( 'Write a message', 'Product page gift form', 'woocommerce-smart-coupons' ),
				'pickDeliveryDateTime' => _x( 'Pick a delivery date & time', 'Product page gift form', 'woocommerce-smart-coupons' ),
				'giftToPerson'         => _x( 'GIFT to person', 'Product page gift form accordion title', 'woocommerce-smart-coupons' ),
				'sessionSaveFailed'    => _x( 'Session save failed', 'Product page gift form error', 'woocommerce-smart-coupons' ),
				'unknownError'         => _x( 'Unknown error', 'Product page gift form error', 'woocommerce-smart-coupons' ),
			);

			wp_localize_script(
				'wc-sc-product-page-gift-form',
				'wcScProductPageGiftForm',
				array(
					'ajaxUrl'           => $ajax_url,
					'ajaxNonce'         => $ajax_nonce,
					'datepickerOptions' => $datepicker_options,
					'i18n'              => $i18n,
				)
			);

			// Enqueue timepicker if schedule feature is enabled.
			$schedule_store_credit = get_option( 'smart_coupons_schedule_store_credit' );
			if ( 'yes' === $schedule_store_credit ) {
				$this->enqueue_timepicker();
			}
		}

		/**
		 * Initialize WooCommerce session on product pages if not already initialized.
		 *
		 * @since 9.64.0
		 * @return void
		 */
		public function maybe_init_wc_session() {
			try {
				// Don't initialize during REST API or AJAX requests.
				if ( ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || wp_doing_ajax() ) {
					return;
				}

				// Only initialize on single product pages.
				if ( ! is_product() || ! is_callable( 'WC' ) || ! is_object( WC() ) ) {
					return;
				}

				// Check if coupon receiver form is enabled (EARLY EXIT).
				$is_show_coupon_receiver_form = get_option( 'smart_coupons_display_coupon_receiver_details_form', 'yes' );
				if ( 'no' === $is_show_coupon_receiver_form ) {
					return; // Don't initialize session if form is disabled.
				}

				// Allow filtering to disable product page form.
				$is_show_product_page_form = apply_filters( 'wc_sc_show_product_page_gift_form', true );
				if ( ! $is_show_product_page_form ) {
					return; // Don't initialize session if form is filtered out.
				}

				// Initialize session if it doesn't exist yet.
				if ( method_exists( WC()->session, 'has_session' ) && ! WC()->session->has_session() ) {
					WC()->session->set_customer_session_cookie( true );
				}
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Enqueue timepicker scripts for product page.
		 *
		 * Loads datetime picker assets only when needed:
		 * - Must be single product page
		 * - Form display must be enabled
		 * - Schedule feature must be enabled
		 *
		 * @return void
		 */
		public function enqueue_product_page_timepicker() {
			// Only enqueue on single product pages.
			if ( ! is_product() ) {
				return;
			}

			// Check if coupon receiver form is enabled (EARLY EXIT).
			$is_show_coupon_receiver_form = get_option( 'smart_coupons_display_coupon_receiver_details_form', 'yes' );
			if ( 'no' === $is_show_coupon_receiver_form ) {
				return; // Don't load scripts if form is disabled.
			}

			// Check if schedule feature is enabled (EARLY EXIT).
			$schedule_store_credit = get_option( 'smart_coupons_schedule_store_credit' );
			if ( 'yes' !== $schedule_store_credit ) {
				return; // Don't load timepicker if schedule feature is disabled.
			}

			// Allow filtering to disable product page form.
			$is_show_product_page_form = apply_filters( 'wc_sc_show_product_page_gift_form', true );
			if ( ! $is_show_product_page_form || $this->wc_sc_is_checkout_block_based() ) {
				return; // Don't load scripts if form is filtered out.
			}

			// All checks passed - enqueue timepicker.
			$this->enqueue_timepicker();
		}

		/**
		 * Get product page gift details from session (separate from checkout session).
		 *
		 * @param int $product_id Product ID.
		 * @return array|null Session data array or null if not available.
		 */
		public function get_product_page_gift_details_session( $product_id ) {
			try {
				// Ensure WooCommerce session is initialized.
				if ( ! is_callable( 'WC' ) || ! is_object( WC() ) ) {
					return null;
				}

				// Initialize session if not already initialized.
				if ( method_exists( WC()->session, 'has_session' ) && ! WC()->session->has_session() ) {
					WC()->session->set_customer_session_cookie( true );
				}

				if ( is_object( WC()->session ) && is_callable( array( WC()->session, 'get' ) ) ) {
					$session_key  = 'wc_sc_product_page_gift_details_' . absint( $product_id );
					$session_data = WC()->session->get( $session_key );

					// Return session data as-is without filtering.
					return $session_data;
				}
				return null;
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
				return null;
			}
		}

		/**
		 * Set product page gift details in session.
		 *
		 * @param int   $product_id  Product ID.
		 * @param array $posted_data Posted data containing gift details.
		 * @return void
		 */
		public function set_product_page_gift_details_session( $product_id, $posted_data = array() ) {
			try {
				// Verify WooCommerce session is available.
				if ( ! is_callable( 'WC' ) || ! is_object( WC() ) || ! is_object( WC()->session ) ) {
					return;
				}

				// Initialize session if needed.
				if ( method_exists( WC()->session, 'has_session' ) && ! WC()->session->has_session() ) {
					WC()->session->set_customer_session_cookie( true );
				}

				$session_data = array();

				// Copy email data (validate format only).
				if ( ! empty( $posted_data['gift_receiver_email'] ) && is_array( $posted_data['gift_receiver_email'] ) ) {
					foreach ( $posted_data['gift_receiver_email'] as $coupon_id => $emails ) {
						if ( is_array( $emails ) ) {
							foreach ( $emails as $idx => $email ) {
								$email = trim( $email );
								if ( ! empty( $email ) && is_email( $email ) ) {
									$session_data['gift_receiver_email'][ $coupon_id ][ $idx ] = $email;
								}
							}
						}
					}
				}

				// Copy message data as-is.
				if ( ! empty( $posted_data['gift_receiver_message'] ) && is_array( $posted_data['gift_receiver_message'] ) ) {
					foreach ( $posted_data['gift_receiver_message'] as $coupon_id => $messages ) {
						if ( is_array( $messages ) ) {
							foreach ( $messages as $idx => $message ) {
								$session_data['gift_receiver_message'][ $coupon_id ][ $idx ] = trim( $message );
							}
						}
					}
				}

				// Copy date/time data as-is.
				if ( ! empty( $posted_data['gift_sending_date_time'] ) && is_array( $posted_data['gift_sending_date_time'] ) ) {
					foreach ( $posted_data['gift_sending_date_time'] as $coupon_id => $dates ) {
						if ( is_array( $dates ) ) {
							foreach ( $dates as $idx => $date ) {
								$session_data['gift_sending_date_time'][ $coupon_id ][ $idx ] = trim( $date );
							}
						}
					}
				}

				// Copy schedule setting as-is.
				if ( isset( $posted_data['wc_sc_schedule_gift_sending'] ) ) {
					$session_data['wc_sc_schedule_gift_sending'] = $posted_data['wc_sc_schedule_gift_sending'];
				}

				// Save to WooCommerce session.
				$session_key = 'wc_sc_product_page_gift_details_' . absint( $product_id );
				WC()->session->set( $session_key, $session_data );
				WC()->session->save_data();
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Normalize array keys for consistent JSON encoding.
		 *
		 * Converts numeric string keys to integers recursively to ensure
		 * proper JSON array formatting instead of objects.
		 *
		 * @since 9.64.0
		 *
		 * @param array $array Array to normalize.
		 * @return array Normalized array with integer keys where applicable.
		 */
		private function normalize_array_keys( $array ) {
			// Return non-arrays as-is.
			if ( ! is_array( $array ) ) {
				return $array;
			}

			$normalized = array();
			foreach ( $array as $key => $value ) {
				// Convert numeric string keys to integers.
				$new_key = is_numeric( $key ) ? (int) $key : $key;

				// Recursively normalize nested arrays.
				if ( is_array( $value ) ) {
					$normalized[ $new_key ] = $this->normalize_array_keys( $value );
				} else {
					$normalized[ $new_key ] = $value;
				}
			}

			return $normalized;
		}

		/**
		 * Clear specific product gift details from session.
		 *
		 * @param int $product_id Product ID.
		 * @return void
		 */
		public function clear_product_page_gift_details_session( $product_id ) {
			// Verify WooCommerce session is available.
			if ( ! is_callable( 'WC' ) || ! is_object( WC() ) || ! is_object( WC()->session ) || ! is_callable( array( WC()->session, 'set' ) ) ) {
				return;
			}

			// Build session key and clear data.
			$session_key = 'wc_sc_product_page_gift_details_' . absint( $product_id );
			WC()->session->set( $session_key, null );
		}

		/**
		 * Merge product page session data with existing checkout session data.
		 *
		 * Simple append logic:
		 * - Product page sends [coupon_id][person_index] format
		 * - Find next index for each coupon: max(existing_indices) + 1
		 * - Append new data at next_index, next_index+1, etc.
		 * - Maintain [0][0] for backward compatibility (set once, never overwrite)
		 *
		 * @since 9.64.0
		 *
		 * @param array      $product_page_session Product page session data to merge.
		 * @param WC_Product $product              Product object (optional).
		 * @return array Merged session data ready for checkout.
		 */
		private function merge_product_page_session_with_checkout( $product_page_session, $product = null ) {
			// Get existing checkout session.
			$checkout_session = $this->get_coupon_receiver_details_session();

			// If no checkout session, process product page data and return.
			if ( empty( $checkout_session ) || ! is_array( $checkout_session ) ) {
				// Apply transformations before returning.
				$product_page_session = $this->apply_session_transformations( $product_page_session );
				return $product_page_session;
			}

			// Start with existing checkout (preserve all data).
			$merged = $checkout_session;

			// Initialize arrays if needed.
			if ( ! isset( $merged['gift_receiver_email'] ) ) {
				$merged['gift_receiver_email'] = array();
			}
			if ( ! isset( $merged['gift_receiver_message'] ) ) {
				$merged['gift_receiver_message'] = array();
			}
			if ( ! isset( $merged['gift_sending_date_time'] ) ) {
				$merged['gift_sending_date_time'] = array();
			}

			// Get coupon IDs that have data in product page session (exclude [0]).
			$product_coupon_ids = array();
			if ( ! empty( $product_page_session['gift_receiver_email'] ) && is_array( $product_page_session['gift_receiver_email'] ) ) {
				foreach ( array_keys( $product_page_session['gift_receiver_email'] ) as $cid ) {
					if ( 0 !== $cid && '0' !== $cid ) {
						$product_coupon_ids[] = $cid;
					}
				}
			}

			// Process each coupon ID from product page.
			foreach ( $product_coupon_ids as $coupon_id ) {
				// Initialize coupon arrays if they don't exist in checkout.
				if ( ! isset( $merged['gift_receiver_email'][ $coupon_id ] ) ) {
					$merged['gift_receiver_email'][ $coupon_id ] = array();
				}
				if ( ! isset( $merged['gift_receiver_message'][ $coupon_id ] ) ) {
					$merged['gift_receiver_message'][ $coupon_id ] = array();
				}
				if ( ! isset( $merged['gift_sending_date_time'][ $coupon_id ] ) ) {
					$merged['gift_sending_date_time'][ $coupon_id ] = array();
				}

				// Find next available index for this coupon in checkout.
				$next_index = 0;
				if ( ! empty( $merged['gift_receiver_email'][ $coupon_id ] ) ) {
					$keys = array_keys( $merged['gift_receiver_email'][ $coupon_id ] );
					if ( ! empty( $keys ) ) {
						$next_index = max( $keys ) + 1;
					}
				}

				// Get product page data for this coupon.
				$pp_emails   = ! empty( $product_page_session['gift_receiver_email'][ $coupon_id ] ) ? $product_page_session['gift_receiver_email'][ $coupon_id ] : array();
				$pp_messages = ! empty( $product_page_session['gift_receiver_message'][ $coupon_id ] ) ? $product_page_session['gift_receiver_message'][ $coupon_id ] : array();
				$pp_dates    = ! empty( $product_page_session['gift_sending_date_time'][ $coupon_id ] ) ? $product_page_session['gift_sending_date_time'][ $coupon_id ] : array();

				// Append each email from product page.
				if ( is_array( $pp_emails ) ) {
					foreach ( $pp_emails as $pp_idx => $email ) {
						$email = trim( $email );

						// Only append valid emails.
						if ( ! empty( $email ) && is_email( $email ) ) {
							// Append at next_index in checkout.
							$merged['gift_receiver_email'][ $coupon_id ][ $next_index ]    = $email;
							$merged['gift_receiver_message'][ $coupon_id ][ $next_index ]  = isset( $pp_messages[ $pp_idx ] ) ? trim( $pp_messages[ $pp_idx ] ) : '';
							$merged['gift_sending_date_time'][ $coupon_id ][ $next_index ] = isset( $pp_dates[ $pp_idx ] ) ? trim( $pp_dates[ $pp_idx ] ) : '';

							++$next_index;
						}
					}
				}
			}

			// Merge schedule setting.
			if ( ! empty( $product_page_session['wc_sc_schedule_gift_sending'] ) ) {
				$merged['wc_sc_schedule_gift_sending'] = $product_page_session['wc_sc_schedule_gift_sending'];
			} elseif ( empty( $merged['wc_sc_schedule_gift_sending'] ) ) {
				$merged['wc_sc_schedule_gift_sending'] = 'no';
			}

			// Apply transformations for timestamps, backward compatibility, and gift metadata.
			$merged = $this->apply_session_transformations( $merged );

			return $merged;
		}

		/**
		 * Apply transformations to session data.
		 *
		 * Handles:
		 * - [0][0] format creation for backward compatibility
		 * - Timestamp conversion
		 * - is_gift/sc_send_to calculation
		 *
		 * @since 9.64.0
		 *
		 * @param array $session_data Session data to transform.
		 * @return array Transformed session data.
		 */
		private function apply_session_transformations( $session_data ) {
			// Create [0][0] format if not exists.
			if ( empty( $session_data['gift_receiver_email'][0][0] ) ) {
				if ( ! empty( $session_data['gift_receiver_email'] ) && is_array( $session_data['gift_receiver_email'] ) ) {
					foreach ( $session_data['gift_receiver_email'] as $cid => $emails ) {
						if ( 0 === $cid || '0' === $cid ) {
							continue;
						}
						if ( is_array( $emails ) ) {
							foreach ( $emails as $idx => $email ) {
								if ( ! empty( $email ) && is_email( $email ) ) {
									$session_data['gift_receiver_email'][0][0]    = $email;
									$session_data['gift_receiver_message'][0][0]  = ! empty( $session_data['gift_receiver_message'][ $cid ][ $idx ] ) ? $session_data['gift_receiver_message'][ $cid ][ $idx ] : '';
									$session_data['gift_sending_date_time'][0][0] = ! empty( $session_data['gift_sending_date_time'][ $cid ][ $idx ] ) ? $session_data['gift_sending_date_time'][ $cid ][ $idx ] : '';
									break 2;
								}
							}
						}
					}
				}
			}

			// Convert timestamps.
			if ( ! empty( $session_data['gift_sending_date_time'] ) ) {
				$session_data['gift_sending_timestamp'] = $this->convert_gift_sending_date_time_to_timestamps( $session_data['gift_sending_date_time'] );
			}

			// Count unique emails for is_gift and sc_send_to.
			$unique_emails = array();
			if ( ! empty( $session_data['gift_receiver_email'] ) && is_array( $session_data['gift_receiver_email'] ) ) {
				foreach ( $session_data['gift_receiver_email'] as $cid => $emails ) {
					if ( is_array( $emails ) ) {
						foreach ( $emails as $email ) {
							if ( ! empty( $email ) && is_email( $email ) ) {
								$normalized = strtolower( trim( $email ) );
								if ( ! in_array( $normalized, $unique_emails, true ) ) {
									$unique_emails[] = $normalized;
								}
							}
						}
					}
				}
			}

			// Set is_gift and sc_send_to.
			$session_data['is_gift']    = ! empty( $unique_emails ) ? 'yes' : 'no';
			$session_data['sc_send_to'] = count( $unique_emails ) > 1 ? 'many' : 'one';

			return $session_data;
		}

		/**
		 * Move product page session data to checkout session on add to cart.
		 *
		 * Ensures gift details are preserved when product is added to cart.
		 *
		 * @since 9.64.0
		 *
		 * @param string $cart_item_key  Cart item key.
		 * @param int    $product_id     Product ID.
		 * @param int    $quantity       Quantity.
		 * @param int    $variation_id   Variation ID.
		 * @param array  $variation      Variation data.
		 * @param array  $cart_item_data Cart item data.
		 * @return void
		 */
		public function move_product_page_session_to_checkout( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
			try {
				// Get product page session data.
				$product_page_session = $this->get_product_page_gift_details_session( $product_id );

				// Only proceed if session data exists.
				if ( is_null( $product_page_session ) || empty( $product_page_session ) ) {
					return;
				}

				// Get product to extract coupon IDs.
				$product = wc_get_product( $product_id );
				if ( ! $product ) {
					return;
				}

				// Merge with existing checkout session data (pass product for coupon ID extraction).
				$merged_session = $this->merge_product_page_session_with_checkout( $product_page_session, $product );

				// Save merged data to checkout session.
				$this->set_coupon_receiver_details_session( $merged_session );

				// Clear product page session after moving to checkout.
				$this->clear_product_page_gift_details_session( $product_id );
			} catch ( \Throwable $e ) {
				// Handle exception gracefully.
				$this->sc_block_catch_error( $e );
			}
		}

		/**
		 * Check if the WooCommerce Checkout page is using the Block-based Checkout.
		 *
		 * This method verifies:
		 * - That WooCommerce Blocks functions exist (wc_is_block_theme)
		 * - That the Checkout page contains the 'woocommerce/checkout' block
		 *
		 * @return bool True if using block-based checkout, false if using classic checkout.
		 */
		public function wc_sc_is_checkout_block_based() {
			try {
				// Ensure WooCommerce functions are available.
				if ( ! function_exists( 'wc_get_page_id' ) || ! function_exists( 'has_block' ) ) {
					return false;
				}

				// Retrieve the Checkout page ID.
				$checkout_page_id = wc_get_page_id( 'checkout' );

				// Validate the page ID and check for the checkout block.
				if ( $checkout_page_id && has_block( 'woocommerce/checkout', $checkout_page_id ) ) {
					return true;
				}

				// Fallback to Classic Checkout if no block is found.
				return false;

			} catch ( \Throwable $e ) {
				// Handle exception gracefully.
				$this->sc_block_catch_error( $e );
				// Return false gracefully to avoid breaking checkout flow.
				return false;
			}
		}

		/**
		 * Save product page coupon receiver details via AJAX.
		 *
		 * Stores gift receiver details in product-specific session.
		 *
		 * @since 9.64.0
		 * @return void
		 */
		public function ajax_save_product_page_coupon_receiver_details() {
			try {
				// Verify nonce for security.
				check_ajax_referer( 'wc-sc-save-product-page-coupon-receiver-details', 'security' );

				// Get and validate product ID.
				$product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
				if ( empty( $product_id ) ) {
					wp_send_json(
						array(
							'success' => 'no',
							'message' => _x( 'Product ID is required.', 'AJAX error message', 'woocommerce-smart-coupons' ),
						)
					);
					return;
				}

				// Parse and save posted data to session.
				wp_parse_str(wc_clean(wp_unslash(urldecode_deep($_POST['data']))), $posted_data); // phpcs:ignore
				$this->set_product_page_gift_details_session( $product_id, $posted_data );

				// Send success response.
				wp_send_json( array( 'success' => 'yes' ) );
			} catch ( \Throwable $e ) {
				// Handle exception gracefully.
				$this->sc_block_catch_error( $e );

				wp_send_json(
					array(
						'success' => 'no',
						'message' => _x( 'Failed to save coupon receiver details.', 'AJAX error message', 'woocommerce-smart-coupons' ),
					)
				);
			}
		}

		/**
		 * Display gift certificate receiver detail form on product page
		 *
		 * This method renders the gift certificate receiver form on single product pages.
		 * It only displays when the product has associated coupons and handles:
		 * - Loading session data for pre-filling form fields
		 * - Rendering coupon data for JavaScript
		 * - Outputting the form HTML structure
		 * - Enqueuing JavaScript for dynamic form behavior
		 *
		 * @since 9.64.0
		 */
		public function product_page_gift_certificate_receiver_detail_form() {
			try {
				global $product;

				// Skip admin pages, AJAX requests, REST endpoints, and product variations.
				if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || wp_is_rest_endpoint() || defined( 'REST_REQUEST' ) || $this->wc_sc_is_checkout_block_based() ) {
					return;
				}

				// Skip if not a product object or is a variation.
				if ( ! is_object( $product ) || ! is_a( $product, 'WC_Product' ) ) {
					return;
				}

				// Skip product variations (compatibility with old and new WooCommerce).
				if ( $product instanceof WC_Product_Variation ) {
					return;
				}

				// Check if coupon receiver form display is enabled (EARLY CHECK FOR OPTIMIZATION).
				$is_show_coupon_receiver_form = get_option( 'smart_coupons_display_coupon_receiver_details_form', 'yes' );
				if ( 'no' === $is_show_coupon_receiver_form ) {
					return; // Exit early - don't load any assets or process data.
				}

				/**
				 * Filters whether to show the gift form on the product page.
				 *
				 * Developers can use this filter to conditionally enable or disable
				 * the gift form displayed on single product pages. This check happens
				 * early, and returning false will prevent the form from rendering.
				 *
				 * @since 9.64.0
				 * @hook wc_sc_show_product_page_gift_form
				 *
				 * @param bool $show Whether to show the product page gift form. Default true.
				 *
				 * @return bool True to show the form, false to hide it.
				 *
				 * @example
				 *     add_filter( 'wc_sc_show_product_page_gift_form', function( $show ) {
				 *         return false; // Hide the product page gift form
				 *     });
				 */
				$is_show_product_page_form = apply_filters( 'wc_sc_show_product_page_gift_form', true );
				if ( ! $is_show_product_page_form ) {
					return; // Exit early if filtered to hide.
				}

				// Get coupon titles for the product.
				$coupon_titles = $this->get_coupon_titles( array( 'product_object' => $product ) );

				// Only show form if product has coupons.
				if ( empty( $coupon_titles ) || ! is_array( $coupon_titles ) ) {
					return;
				}

				// Get product ID (compatibility with old and new WooCommerce).
				$product_id = ( is_object( $product ) && is_callable( array( $product, 'get_id' ) ) ) ? $product->get_id() : 0;
				if ( empty( $product_id ) ) {
					return;
				}

				// Get product page session data (raw form data only).
				$product_page_session = $this->get_product_page_gift_details_session( $product_id );

				// Extract raw form data for JS to display.
				$wc_sc_schedule_gift_sending = '';
				$gift_receiver_email         = array();
				$gift_sending_date_time      = array();
				$gift_receiver_message       = array();

				if ( ! is_null( $product_page_session ) && is_array( $product_page_session ) && ! empty( $product_page_session ) ) {
					$wc_sc_schedule_gift_sending = ( ! empty( $product_page_session['wc_sc_schedule_gift_sending'] ) ) ? wc_clean( wp_unslash( $product_page_session['wc_sc_schedule_gift_sending'] ) ) : '';
					$gift_receiver_email         = ( ! empty( $product_page_session['gift_receiver_email'] ) && is_array( $product_page_session['gift_receiver_email'] ) ) ? wc_clean( wp_unslash( $product_page_session['gift_receiver_email'] ) ) : array();
					$gift_sending_date_time      = ( ! empty( $product_page_session['gift_sending_date_time'] ) && is_array( $product_page_session['gift_sending_date_time'] ) ) ? wc_clean( wp_unslash( $product_page_session['gift_sending_date_time'] ) ) : array();
					$gift_receiver_message       = ( ! empty( $product_page_session['gift_receiver_message'] ) && is_array( $product_page_session['gift_receiver_message'] ) ) ? wc_clean( wp_unslash( $product_page_session['gift_receiver_message'] ) ) : array();
				}

				// Get plugin settings.
				$schedule_store_credit                           = get_option( 'smart_coupons_schedule_store_credit' );
				$smart_coupon_gift_certificate_form_page_text    = get_option( 'smart_coupon_gift_certificate_form_page_text' );
				$smart_coupon_gift_certificate_form_page_text    = ! empty( $smart_coupon_gift_certificate_form_page_text ) ? $smart_coupon_gift_certificate_form_page_text : _x( 'Send Coupons to...', 'Product page gift form title', 'woocommerce-smart-coupons' );
				$smart_coupon_gift_certificate_form_details_text = get_option( 'smart_coupon_gift_certificate_form_details_text' );
				$smart_coupon_gift_certificate_form_details_text = ! empty( $smart_coupon_gift_certificate_form_details_text ) ? $smart_coupon_gift_certificate_form_details_text : '';

				// Prepare coupon data for JavaScript.
				$coupons_data = array();
				foreach ( $coupon_titles as $coupon_title ) {
					$coupon = new WC_Coupon( $coupon_title );

					// Get coupon data (compatibility with old and new WooCommerce).
					if ( ! is_object( $coupon ) ) {
						continue;
					}

					// Get coupon ID (compatibility check).
					if ( is_callable( array( $coupon, 'get_id' ) ) ) {
						$coupon_id = $coupon->get_id();
					} else {
						$coupon_id = ( ! empty( $coupon->id ) ) ? $coupon->id : 0;
					}

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

					// Get coupon code (compatibility check).
					$coupon_code = ( is_callable( array( $coupon, 'get_code' ) ) ) ? $coupon->get_code() : ( ( ! empty( $coupon->code ) ) ? $coupon->code : '' );

					// Get discount type (compatibility check).
					$discount_type = ( is_callable( array( $coupon, 'get_discount_type' ) ) ) ? $coupon->get_discount_type() : ( ( ! empty( $coupon->discount_type ) ) ? $coupon->discount_type : '' );

					// Get free shipping status (compatibility check).
					if ( is_callable( array( $coupon, 'get_free_shipping' ) ) ) {
						$is_free_shipping = $coupon->get_free_shipping() ? 'yes' : 'no';
					} else {
						$is_free_shipping = ( ! empty( $coupon->free_shipping ) ) ? $coupon->free_shipping : '';
					}

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

					// Get formatted coupon text and amount - match checkout format exactly.
					$coupon_data             = $this->get_coupon_meta_data( $coupon );
					$formatted_coupon_text   = '';
					$formatted_coupon_amount = '';

					// Calculate coupon amount like checkout does.
					global $woocommerce_smart_coupon;

					// Get meta data (compatibility with old and new WooCommerce).
					$pick_price_of_prod    = ( is_callable( array( $coupon, 'get_meta' ) ) ) ? $coupon->get_meta( 'is_pick_price_of_product' ) : get_post_meta( $coupon_id, 'is_pick_price_of_product', true );
					$sell_sc_at_less_price = get_option( 'smart_coupons_sell_store_credit_at_less_price', 'no' );

					// Check if coupon amount should be picked from product price.
					if ( is_callable( array( $woocommerce_smart_coupon, 'is_coupon_amount_pick_from_product_price' ) ) && $woocommerce_smart_coupon->is_coupon_amount_pick_from_product_price( array( $coupon_code ) ) ) {
						if ( 'yes' === $sell_sc_at_less_price ) {
							// Use regular price if available, otherwise use sale price.
							$_coupon_amount = ( is_callable( array( $product, 'get_regular_price' ) ) ) ? $product->get_regular_price() : '';
							if ( empty( $_coupon_amount ) ) {
								$_coupon_amount = ( is_callable( array( $product, 'get_price' ) ) ) ? $product->get_price() : 0;
							}
						} else {
							$_coupon_amount = ( is_callable( array( $product, 'get_price' ) ) ) ? $product->get_price() : 0;
						}
					} else {
						$_coupon_amount = $coupon_amount;
					}

					if ( ! empty( $_coupon_amount ) || $_coupon_amount > 0 || $coupon_amount > 0 || 'yes' === $is_free_shipping ) {
						$formatted_coupon_amount = ( $coupon_amount <= 0 ) ? wc_price( $_coupon_amount ) : $coupon_data['coupon_amount'];
						$formatted_coupon_text  .= $coupon_data['coupon_type'];
						if ( 'yes' === $is_free_shipping ) {
							$formatted_coupon_text .= ' &amp; ';
						}
					}
					if ( 'yes' === $is_free_shipping ) {
						$formatted_coupon_text .= _x( 'Free Shipping coupon', 'Coupon type label', 'woocommerce-smart-coupons' );
					}
					if ( 'smart_coupon' !== $discount_type && false === strpos( $formatted_coupon_text, 'coupon' ) ) {
						$formatted_coupon_text .= ' ' . _x( 'coupon', 'Coupon type suffix', 'woocommerce-smart-coupons' );
					}

					// Check if this coupon uses credit_called (picks price from product).
					$uses_credit_called = false;
					if ( is_callable( array( $woocommerce_smart_coupon, 'is_coupon_amount_pick_from_product_price' ) ) && $woocommerce_smart_coupon->is_coupon_amount_pick_from_product_price( array( $coupon_code ) ) ) {
						// Check if product has no fixed price (price is 0 or empty).
						$product_price = ( is_callable( array( $product, 'get_price' ) ) ) ? $product->get_price() : 0;
						if ( empty( $product_price ) || $product_price <= 0 ) {
							$uses_credit_called = true;
							// Ensure formatted_text is set for credit_called coupons even with no amount.
							if ( empty( $formatted_coupon_text ) ) {
								$formatted_coupon_text = $coupon_data['coupon_type'];
								if ( 'smart_coupon' !== $discount_type && false === strpos( $formatted_coupon_text, 'coupon' ) ) {
									$formatted_coupon_text .= ' ' . _x( 'coupon', 'Coupon type suffix', 'woocommerce-smart-coupons' );
								}
							}
						}
					}

					$coupons_data[] = array(
						'id'                 => $coupon_id,
						'code'               => $coupon_code,
						'title'              => $coupon_title,
						'formatted_text'     => $formatted_coupon_text,
						'formatted_amount'   => $formatted_coupon_amount, // This is HTML formatted like checkout.
						'uses_credit_called' => $uses_credit_called, // Whether this coupon uses credit_called input.
					);
				}

				// Get default accordion state from filter.
				$default_accordion_state = apply_filters( 'wc_sc_gift_form_default_accordion_state', 'expanded' );
				?>
				<div class="wc-sc-gift-card-receiver-detail-container wc-sc-product-page-gift-form"
					data-coupons='<?php echo esc_attr( wp_json_encode( $coupons_data ) ); ?>'
					data-schedule-enabled="<?php echo esc_attr( $schedule_store_credit ); ?>"
					data-accordion-state="<?php echo esc_attr( $default_accordion_state ); ?>"
					data-product-id="<?php echo esc_attr( $product_id ); ?>"
					data-currency-symbol="<?php echo esc_attr( get_woocommerce_currency_symbol() ); ?>"
					data-currency-position="<?php echo esc_attr( get_option( 'woocommerce_currency_pos' ) ); ?>"
					data-price-decimals="<?php echo esc_attr( wc_get_price_decimals() ); ?>"
					data-price-decimal-sep="<?php echo esc_attr( wc_get_price_decimal_separator() ); ?>"
					data-price-thousand-sep="<?php echo esc_attr( wc_get_price_thousand_separator() ); ?>"
					data-session-data='
				<?php
				// Only pass raw form data to JS (no calculated values).
				$session_data_array = array(
					'wc_sc_schedule_gift_sending' => $wc_sc_schedule_gift_sending,
					'gift_receiver_email'         => $gift_receiver_email,
					'gift_sending_date_time'      => $gift_sending_date_time,
					'gift_receiver_message'       => $gift_receiver_message,
				);
				// Normalize array keys for JSON.
				if ( ! empty( $gift_receiver_email ) && is_array( $gift_receiver_email ) ) {
					$session_data_array['gift_receiver_email'] = $this->normalize_array_keys( $gift_receiver_email );
				}
				if ( ! empty( $gift_receiver_message ) && is_array( $gift_receiver_message ) ) {
					$session_data_array['gift_receiver_message'] = $this->normalize_array_keys( $gift_receiver_message );
				}
				if ( ! empty( $gift_sending_date_time ) && is_array( $gift_sending_date_time ) ) {
					$session_data_array['gift_sending_date_time'] = $this->normalize_array_keys( $gift_sending_date_time );
				}
				echo esc_attr( wp_json_encode( $session_data_array ) );
				?>
									'>
					<label for="wc-sc-gift-title"><?php echo esc_html( stripslashes( $smart_coupon_gift_certificate_form_page_text ) ); ?></label>
					<?php if ( ! empty( $smart_coupon_gift_certificate_form_details_text ) ) { ?>
						<p><?php echo esc_html( stripslashes( $smart_coupon_gift_certificate_form_details_text ) ); ?></p>
					<?php } ?>

					<div class="gift-certificate-receiver-detail-form wc-sc-product-gift-form-content">
						<!-- Accordions container - will be populated by JavaScript -->
						<!-- Structure: Each accordion = one person, contains forms for all coupons -->
						<div id="wc_sc_product_gift_form_accordions">
							<!-- Accordions will be generated by JavaScript based on quantity -->
						</div>
					</div>
				</div>
				<?php
			} catch ( \Throwable $e ) {
				$this->sc_block_catch_error( $e );
			}
		}
	}

}

WC_SC_Purchase_Credit::get_instance();
