<?php
/**
 * Storzen Module — Quick View
 *
 * Adds a "Quick View" button on shop loop items that opens a modal with the
 * product gallery, summary, price, variations, and AJAX add-to-cart.
 *
 * Works with:
 *   • Simple products
 *   • Variable products (custom attribute selector + variation resolver)
 *   • Grouped / external (gracefully degrade to "View full details")
 *
 * Compatibility:
 *   • Classic + Block themes
 *   • HPOS (uses wc_get_product() only)
 *   • Elementor product templates
 *   • Translation-ready ('storzen' text domain)
 *
 * Reads its settings from the Storzen_Modules registry (no separate option key).
 *
 * @package storzen
 * @since   1.1.0
 */

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

if ( ! class_exists( 'Storzen_Module_Quick_View' ) ) {

	class Storzen_Module_Quick_View {

		/** AJAX action — fetch modal HTML */
		const AJAX_FETCH = 'storzen_quick_view';

		/** AJAX action — add to cart from modal */
		const AJAX_ATC = 'storzen_quick_view_add_to_cart';

		/** @var array Local cache of resolved settings (per request) */
		private $settings = null;

		public function __construct() {
			if ( ! function_exists( 'WC' ) ) {
				return;
			}

			// Frontend assets.
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );

			// Inject the trigger button at the configured loop position.
			$position = $this->get_setting( 'button_position' );
			if ( 'on-image' === $position ) {
				// Renders inside the image link wrapper.
				add_action( 'woocommerce_before_shop_loop_item_title', array( $this, 'render_button' ), 11 );
			} elseif ( 'after-title' === $position ) {
				add_action( 'woocommerce_after_shop_loop_item_title', array( $this, 'render_button' ), 14 );
			} else { // after-item
				add_action( 'woocommerce_after_shop_loop_item', array( $this, 'render_button' ), 14 );
			}

			// Storzen-native hook listeners — fired by Storzen Elementor grid
			// templates so the Quick View button appears on imported shop pages.
			// Storzen overlay hook lives inside the card image action area,
			// which is the perfect spot for a Quick View icon regardless of
			// the user-selected button_position above. We render a dedicated
			// always-visible overlay icon here (the 'on-image' hover variant
			// relies on WooCommerce's own .products .product markup, which the
			// Storzen Elementor grid does not output).
			add_action( 'storzen_shop_card_overlay', array( $this, 'render_button_overlay' ), 14, 1 );

			// Modal shell (once per page, in footer).
			add_action( 'wp_footer', array( $this, 'render_modal_shell' ) );

			// AJAX endpoints (logged-in + guest).
			add_action( 'wp_ajax_'        . self::AJAX_FETCH, array( $this, 'ajax_fetch_product' ) );
			add_action( 'wp_ajax_nopriv_' . self::AJAX_FETCH, array( $this, 'ajax_fetch_product' ) );

			add_action( 'wp_ajax_'        . self::AJAX_ATC, array( $this, 'ajax_add_to_cart' ) );
			add_action( 'wp_ajax_nopriv_' . self::AJAX_ATC, array( $this, 'ajax_add_to_cart' ) );
		}

		// ─────────────────────────────────────────────────────────────────
		// Settings helper
		// ─────────────────────────────────────────────────────────────────

		/**
		 * Get a module setting with safe defaults.
		 *
		 * @param string $key Setting key.
		 * @return mixed
		 */
		private function get_setting( $key ) {
			if ( null === $this->settings ) {
				$this->settings = array(
					'btn_text'         => (string) storzen_module_setting( 'quick_view', 'btn_text' ),
					'button_position'  => (string) storzen_module_setting( 'quick_view', 'button_position' ),
					'icon'             => (string) storzen_module_setting( 'quick_view', 'icon' ),
					'show_gallery'     => (bool)   storzen_module_setting( 'quick_view', 'show_gallery' ),
					'ajax_add_to_cart' => (bool)   storzen_module_setting( 'quick_view', 'ajax_add_to_cart' ),
					'show_sku'         => (bool)   storzen_module_setting( 'quick_view', 'show_sku' ),
					'show_categories'  => (bool)   storzen_module_setting( 'quick_view', 'show_categories' ),
					'show_tags'        => (bool)   storzen_module_setting( 'quick_view', 'show_tags' ),
				);

				// Sane fallbacks if the registry returned empty values.
				if ( '' === $this->settings['btn_text'] ) {
					$this->settings['btn_text'] = __( 'Quick View', 'storzen' );
				}
				if ( ! in_array( $this->settings['button_position'], array( 'on-image', 'after-title', 'after-item' ), true ) ) {
					$this->settings['button_position'] = 'on-image';
				}
				if ( ! in_array( $this->settings['icon'], array( 'eye', 'search', 'plus', 'none' ), true ) ) {
					$this->settings['icon'] = 'eye';
				}
			}
			return isset( $this->settings[ $key ] ) ? $this->settings[ $key ] : null;
		}

		// ─────────────────────────────────────────────────────────────────
		// Asset enqueue
		// ─────────────────────────────────────────────────────────────────

		/**
		 * Determine if the current request is a shop-like page where Quick View should run.
		 *
		 * @return bool
		 */
		private function is_shop_context() {
			if ( ! function_exists( 'is_woocommerce' ) ) {
				return false;
			}
			return (
				is_shop()
				|| is_product_category()
				|| is_product_tag()
				|| is_product()
				|| ( function_exists( 'is_search' ) && is_search() )
			);
		}

		public function enqueue_assets() {
			if ( is_admin() ) {
				return;
			}

			// Load on standard WC shop/archive/single pages, OR on any singular
			// page that may contain an Archive Products Grid widget with Quick View
			// enabled. We cannot check is_page_module_enabled() here (too early —
			// widgets haven't rendered yet), so we load on all singular pages and
			// let render_button()'s is_module_active() guard actual output.
			$load = $this->is_shop_context() || is_singular();
			if ( ! $load ) {
				return;
			}

			wp_enqueue_style(
				'storzen-quick-view',
				STORZEN_ROOT_URL . 'assets/css/modules/quick-view.css',
				array(),
				STORZEN_VERSION
			);

			wp_enqueue_script(
				'storzen-quick-view',
				STORZEN_ROOT_URL . 'assets/js/modules/quick-view.js',
				array( 'jquery' ),
				STORZEN_VERSION,
				true
			);

			wp_localize_script(
				'storzen-quick-view',
				'szQuickView',
				array(
					'ajaxUrl' => admin_url( 'admin-ajax.php' ),
					'i18n'    => array(
						'loading'       => __( 'Loading…', 'storzen' ),
						'error'         => __( 'Could not load product. Please try again.', 'storzen' ),
						'adding'        => __( 'Adding…', 'storzen' ),
						'added'         => __( 'Added to cart!', 'storzen' ),
						'selectOptions' => __( 'Select options', 'storzen' ),
						'addToCart'     => __( 'Add to cart', 'storzen' ),
						'outOfStock'    => __( 'Out of stock', 'storzen' ),
					),
				)
			);
		}

		// ─────────────────────────────────────────────────────────────────
		// Trigger button (loop)
		// ─────────────────────────────────────────────────────────────────

		/**
		 * Render the Quick View button for the current loop product.
		 *
		 * @param WC_Product|null $product_arg Product (passed by Storzen hooks).
		 * @param string          $force_position Optional position override. When
		 *                        set to 'overlay', renders a compact icon-only
		 *                        button that is always visible (used inside the
		 *                        Storzen card overlay area).
		 */
		public function render_button( $product_arg = null, $force_position = '' ) {
			if ( class_exists( 'Elementor\Storzen_Archive_Grid' ) ) {
				$ctx = \Elementor\Storzen_Archive_Grid::is_module_active( 'quick_view' );
				if ( false === $ctx ) {
					return;
				}
			}
			$product = ( $product_arg instanceof WC_Product ) ? $product_arg : ( $GLOBALS['product'] ?? null );
			if ( ! $product instanceof WC_Product ) {
				return;
			}

			$icon_map = array(
				'eye'    => 'far fa-eye',
				'search' => 'fas fa-magnifying-glass',
				'plus'   => 'fas fa-plus',
				'none'   => '',
			);
			$icon_key   = $this->get_setting( 'icon' );
			$icon_class = isset( $icon_map[ $icon_key ] ) ? $icon_map[ $icon_key ] : '';

			$is_overlay = ( 'overlay' === $force_position );
			$position   = $is_overlay ? 'overlay' : $this->get_setting( 'button_position' );
			$classes    = 'sz-qv-btn sz-qv-btn--' . sanitize_html_class( $position );
			$btn_text   = $this->get_setting( 'btn_text' );

			// Overlay: always show an icon; fall back to eye if none configured.
			if ( $is_overlay && '' === $icon_class ) {
				$icon_class = 'far fa-eye';
			}

			// Per-product nonce — prevents reuse across products.
			$nonce = wp_create_nonce( 'storzen_quick_view_' . $product->get_id() );
			?>
			<button
				type="button"
				class="<?php echo esc_attr( $classes ); ?>"
				data-product-id="<?php echo esc_attr( $product->get_id() ); ?>"
				data-nonce="<?php echo esc_attr( $nonce ); ?>"
				title="<?php echo esc_attr( $btn_text ); ?>"
				aria-label="<?php
					/* translators: %s: product name */
					echo esc_attr( sprintf( __( 'Quick view of %s', 'storzen' ), $product->get_name() ) );
				?>"
			>
				<?php if ( '' !== $icon_class ) : ?>
					<i class="<?php echo esc_attr( $icon_class ); ?>" aria-hidden="true"></i>
				<?php endif; ?>
				<span class="sz-qv-btn__label"><?php echo esc_html( $btn_text ); ?></span>
			</button>
			<?php
		}

		/**
		 * Render the Quick View trigger inside the Storzen card overlay area.
		 *
		 * The Storzen Elementor grid does not use WooCommerce's
		 * `.products .product` markup, so the default 'on-image' hover variant
		 * (opacity:0 until card hover) would stay invisible. This wrapper forces
		 * the always-visible compact 'overlay' variant instead.
		 *
		 * @param WC_Product|null $product_arg Product passed by the hook.
		 */
		public function render_button_overlay( $product_arg = null ) {
			$this->render_button( $product_arg, 'overlay' );
		}

		// ─────────────────────────────────────────────────────────────────
		// Modal shell (footer)
		// ─────────────────────────────────────────────────────────────────

		/**
		 * Render the hidden modal container in the page footer.
		 */
		public function render_modal_shell() {
			if ( ! $this->is_shop_context() && ! is_singular() ) {
				return;
			}
			// On singular pages, only render if Quick View is active for this page.
			if ( ! $this->is_shop_context() && is_singular() ) {
				if ( class_exists( 'Elementor\Storzen_Archive_Grid' ) ) {
					$page_ctx = \Elementor\Storzen_Archive_Grid::is_page_module_enabled( 'quick_view' );
					if ( true !== $page_ctx ) {
						return;
					}
				} else {
					return;
				}
			}
			?>
			<div
				class="sz-qv-modal"
				id="sz-qv-modal"
				role="dialog"
				aria-modal="true"
				aria-label="<?php esc_attr_e( 'Product quick view', 'storzen' ); ?>"
				hidden
			>
				<div class="sz-qv-modal__backdrop" data-sz-qv-close="1"></div>
				<div class="sz-qv-modal__wrap" role="document">
					<button
						type="button"
						class="sz-qv-modal__close"
						data-sz-qv-close="1"
						aria-label="<?php esc_attr_e( 'Close quick view', 'storzen' ); ?>"
					>&times;</button>
					<div class="sz-qv-modal__content">
						<div class="sz-qv-modal__loading">
							<div class="sz-qv-spinner" aria-hidden="true"></div>
							<span class="screen-reader-text"><?php esc_html_e( 'Loading product…', 'storzen' ); ?></span>
						</div>
					</div>
				</div>
			</div>
			<?php
		}

		// ─────────────────────────────────────────────────────────────────
		// AJAX — fetch modal product HTML
		// ─────────────────────────────────────────────────────────────────

		/**
		 * AJAX: return the rendered modal HTML for a given product.
		 */
		public function ajax_fetch_product() {
			$product_id = isset( $_POST['product_id'] ) ? absint( wp_unslash( $_POST['product_id'] ) ) : 0;
			$nonce      = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';

			if ( ! $product_id || ! wp_verify_nonce( $nonce, 'storzen_quick_view_' . $product_id ) ) {
				wp_send_json_error( array( 'message' => __( 'Invalid request.', 'storzen' ) ), 400 );
			}

			$product = wc_get_product( $product_id );
			if ( ! $product || ! $product->is_visible() ) {
				wp_send_json_error( array( 'message' => __( 'Product unavailable.', 'storzen' ) ), 404 );
			}

			// Setup WC globals so WC template tags work inside the modal.
			global $post;
			$post = get_post( $product_id ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Required for WC hooks/templates.
			setup_postdata( $post );
			wc_setup_product_data( $post );

			$html = $this->build_modal_html( $product );

			wp_reset_postdata();

			wp_send_json_success( array( 'html' => $html ) );
		}

		/**
		 * Build the full product HTML returned inside the modal.
		 *
		 * @param WC_Product $product Product object.
		 * @return string
		 */
		private function build_modal_html( WC_Product $product ) {
			$show_gallery    = (bool) $this->get_setting( 'show_gallery' );
			$show_sku        = (bool) $this->get_setting( 'show_sku' );
			$show_categories = (bool) $this->get_setting( 'show_categories' );
			$show_tags       = (bool) $this->get_setting( 'show_tags' );

			ob_start();
			?>
			<div class="sz-qv-product" data-product-id="<?php echo esc_attr( $product->get_id() ); ?>">

				<?php if ( $show_gallery ) : ?>
					<div class="sz-qv-product__gallery">
						<?php $this->render_gallery( $product ); ?>
					</div>
				<?php endif; ?>

				<div class="sz-qv-product__summary">

					<h2 class="sz-qv-product__title">
						<?php echo esc_html( $product->get_name() ); ?>
					</h2>

					<div class="sz-qv-product__price">
						<?php echo wp_kses_post( $product->get_price_html() ); ?>
					</div>

					<?php if ( $product->get_rating_count() > 0 ) : ?>
						<div class="sz-qv-product__rating">
							<?php echo wc_get_rating_html( $product->get_average_rating() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- WC helper returns safe HTML. ?>
							<span class="sz-qv-product__rating-count">
								(<?php echo esc_html( $product->get_review_count() ); ?>)
							</span>
						</div>
					<?php endif; ?>

					<?php
					$short_desc = $product->get_short_description();
					if ( $short_desc ) :
						?>
						<div class="sz-qv-product__short-desc">
							<?php echo wp_kses_post( wpautop( $short_desc ) ); ?>
						</div>
					<?php endif; ?>

					<?php if ( $product->is_purchasable() && $product->is_in_stock() ) : ?>
						<div class="sz-qv-product__add-to-cart">
							<?php $this->render_add_to_cart_form( $product ); ?>
						</div>
					<?php else : ?>
						<p class="sz-qv-product__unavailable">
							<?php esc_html_e( 'This product is not available right now.', 'storzen' ); ?>
						</p>
					<?php endif; ?>

					<div class="sz-qv-product__meta">

						<?php if ( $show_sku && $product->get_sku() ) : ?>
							<div class="sz-qv-product__meta-item">
								<span class="sz-qv-product__meta-label"><?php esc_html_e( 'SKU:', 'storzen' ); ?></span>
								<span><?php echo esc_html( $product->get_sku() ); ?></span>
							</div>
						<?php endif; ?>

						<?php
						if ( $show_categories ) {
							$cats = wc_get_product_category_list( $product->get_id(), ', ' );
							if ( $cats ) :
								?>
								<div class="sz-qv-product__meta-item">
									<span class="sz-qv-product__meta-label"><?php esc_html_e( 'Categories:', 'storzen' ); ?></span>
									<span><?php echo wp_kses_post( $cats ); ?></span>
								</div>
								<?php
							endif;
						}

						if ( $show_tags ) {
							$tags = wc_get_product_tag_list( $product->get_id(), ', ' );
							if ( $tags ) :
								?>
								<div class="sz-qv-product__meta-item">
									<span class="sz-qv-product__meta-label"><?php esc_html_e( 'Tags:', 'storzen' ); ?></span>
									<span><?php echo wp_kses_post( $tags ); ?></span>
								</div>
								<?php
							endif;
						}
						?>
					</div>

					<a href="<?php echo esc_url( $product->get_permalink() ); ?>" class="sz-qv-product__view-full">
						<?php esc_html_e( 'View full details →', 'storzen' ); ?>
					</a>

				</div>
			</div>
			<?php
			return ob_get_clean();
		}

		/**
		 * Render the product image gallery (main + thumbs).
		 *
		 * @param WC_Product $product Product object.
		 */
		private function render_gallery( WC_Product $product ) {
			$main_image_id = $product->get_image_id();
			$gallery_ids   = $product->get_gallery_image_ids();

			if ( $main_image_id ) {
				array_unshift( $gallery_ids, $main_image_id );
			}

			if ( empty( $gallery_ids ) ) {
				echo '<div class="sz-qv-gallery__placeholder">' . esc_html__( 'No image available', 'storzen' ) . '</div>';
				return;
			}
			?>
			<div class="sz-qv-gallery">
				<div class="sz-qv-gallery__main">
					<?php
					echo wp_get_attachment_image(
						$gallery_ids[0],
						'large',
						false,
						array( 'class' => 'sz-qv-gallery__main-img' )
					);
					?>
				</div>

				<?php if ( count( $gallery_ids ) > 1 ) : ?>
					<div class="sz-qv-gallery__thumbs">
						<?php foreach ( $gallery_ids as $idx => $id ) : ?>
							<button
								type="button"
								class="sz-qv-gallery__thumb<?php echo 0 === $idx ? ' is-active' : ''; ?>"
								data-image="<?php echo esc_url( (string) wp_get_attachment_image_url( $id, 'large' ) ); ?>"
								aria-label="<?php esc_attr_e( 'View image', 'storzen' ); ?>"
							>
								<?php echo wp_get_attachment_image( $id, 'thumbnail' ); ?>
							</button>
						<?php endforeach; ?>
					</div>
				<?php endif; ?>
			</div>
			<?php
		}

		/**
		 * Render the add-to-cart form (simple, variable, or other types).
		 *
		 * @param WC_Product $product Product object.
		 */
		private function render_add_to_cart_form( WC_Product $product ) {
			if ( $product->is_type( 'variable' ) ) {
				$this->render_variable_form( $product );
			} elseif ( $product->is_type( 'simple' ) ) {
				$this->render_simple_form( $product );
			} else {
				// Grouped / external / other — link to product page.
				?>
				<a href="<?php echo esc_url( $product->get_permalink() ); ?>" class="sz-qv-add-btn">
					<?php echo esc_html( $product->single_add_to_cart_text() ); ?>
				</a>
				<?php
			}
		}

		/**
		 * Simple product cart form.
		 *
		 * @param WC_Product $product Product object.
		 */
		private function render_simple_form( WC_Product $product ) {
			$max = $product->get_max_purchase_quantity();
			?>
			<form
				class="sz-qv-cart-form"
				data-product-id="<?php echo esc_attr( $product->get_id() ); ?>"
				data-type="simple"
			>
				<div class="sz-qv-qty">
					<label for="sz-qv-qty-input-<?php echo esc_attr( $product->get_id() ); ?>" class="screen-reader-text">
						<?php esc_html_e( 'Quantity', 'storzen' ); ?>
					</label>
					<input
						type="number"
						id="sz-qv-qty-input-<?php echo esc_attr( $product->get_id() ); ?>"
						name="quantity"
						value="1"
						min="1"
						<?php echo $max > 0 ? 'max="' . esc_attr( $max ) . '"' : ''; ?>
						class="sz-qv-qty__input"
					>
				</div>
				<button type="submit" class="sz-qv-add-btn" data-action="add-to-cart">
					<?php echo esc_html( $product->single_add_to_cart_text() ); ?>
				</button>
			</form>
			<?php
		}

		/**
		 * Variable product form with attribute dropdowns.
		 *
		 * @param WC_Product $product Variable product.
		 */
		private function render_variable_form( WC_Product $product ) {
			$attributes = $product->get_variation_attributes();
			$variations = $product->get_available_variations();

			if ( empty( $attributes ) ) {
				echo '<p>' . esc_html__( 'No options available.', 'storzen' ) . '</p>';
				return;
			}
			?>
			<form
				class="sz-qv-cart-form sz-qv-cart-form--variable"
				data-product-id="<?php echo esc_attr( $product->get_id() ); ?>"
				data-type="variable"
				data-variations="<?php echo esc_attr( wp_json_encode( $variations ) ); ?>"
			>
				<?php foreach ( $attributes as $attribute_name => $options ) : ?>
					<?php $field_id = 'sz-qv-attr-' . sanitize_title( $attribute_name ) . '-' . $product->get_id(); ?>
					<div class="sz-qv-attribute">
						<label for="<?php echo esc_attr( $field_id ); ?>">
							<?php echo esc_html( wc_attribute_label( $attribute_name ) ); ?>
						</label>
						<select
							id="<?php echo esc_attr( $field_id ); ?>"
							name="attribute_<?php echo esc_attr( sanitize_title( $attribute_name ) ); ?>"
							class="sz-qv-attribute__select"
							data-attribute_name="attribute_<?php echo esc_attr( sanitize_title( $attribute_name ) ); ?>"
						>
							<option value="">
								<?php
								/* translators: %s: attribute name */
								printf( esc_html__( 'Choose %s', 'storzen' ), esc_html( wc_attribute_label( $attribute_name ) ) );
								?>
							</option>
							<?php foreach ( $options as $option ) : ?>
								<option value="<?php echo esc_attr( $option ); ?>">
									<?php echo esc_html( $option ); ?>
								</option>
							<?php endforeach; ?>
						</select>
					</div>
				<?php endforeach; ?>

				<input type="hidden" name="variation_id" class="sz-qv-variation-id" value="0">

				<div class="sz-qv-variation-info" hidden>
					<span class="sz-qv-variation-price"></span>
					<span class="sz-qv-variation-stock"></span>
				</div>

				<div class="sz-qv-qty">
					<input type="number" name="quantity" value="1" min="1" class="sz-qv-qty__input">
				</div>

				<button type="submit" class="sz-qv-add-btn" data-action="add-to-cart" disabled>
					<?php esc_html_e( 'Select options', 'storzen' ); ?>
				</button>
			</form>
			<?php
		}

		// ─────────────────────────────────────────────────────────────────
		// AJAX — Add to cart from modal
		// ─────────────────────────────────────────────────────────────────

		/**
		 * AJAX: handle add-to-cart submission from the modal.
		 */
		public function ajax_add_to_cart() {
			$product_id = isset( $_POST['product_id'] ) ? absint( wp_unslash( $_POST['product_id'] ) ) : 0;
			$nonce      = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';

			if ( ! $product_id || ! wp_verify_nonce( $nonce, 'storzen_quick_view_' . $product_id ) ) {
				wp_send_json_error( array( 'message' => __( 'Invalid request.', 'storzen' ) ), 400 );
			}

			$product = wc_get_product( $product_id );
			if ( ! $product || ! $product->is_purchasable() || ! $product->is_in_stock() ) {
				wp_send_json_error( array( 'message' => __( 'Product unavailable.', 'storzen' ) ), 400 );
			}

			$variation_id = isset( $_POST['variation_id'] ) ? absint( wp_unslash( $_POST['variation_id'] ) ) : 0;
			$quantity     = isset( $_POST['quantity'] ) ? max( 1, absint( wp_unslash( $_POST['quantity'] ) ) ) : 1;
			$variation    = array();

			if ( isset( $_POST['variation'] ) && is_array( $_POST['variation'] ) ) {
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in loop.
				$raw_variation = wp_unslash( $_POST['variation'] );
				foreach ( $raw_variation as $k => $v ) {
					$variation[ sanitize_key( $k ) ] = sanitize_text_field( (string) $v );
				}
			}

			if ( ! WC()->cart ) {
				wp_send_json_error( array( 'message' => __( 'Cart is unavailable.', 'storzen' ) ), 500 );
			}

			$added = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation );

			if ( ! $added ) {
				$notices = wc_get_notices( 'error' );
				$message = '';
				if ( ! empty( $notices ) && isset( $notices[0]['notice'] ) ) {
					$message = wp_strip_all_tags( $notices[0]['notice'] );
				}
				if ( '' === $message ) {
					$message = __( 'Could not add to cart.', 'storzen' );
				}
				wc_clear_notices();
				wp_send_json_error( array( 'message' => $message ), 400 );
			}

			// Build cart fragments so mini-carts/badges refresh.
			$fragments = array();
			if ( function_exists( 'woocommerce_mini_cart' ) ) {
				ob_start();
				woocommerce_mini_cart();
				$mini_cart = ob_get_clean();

				$fragments = apply_filters(
					'woocommerce_add_to_cart_fragments', // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core WC filter.
					array(
						'div.widget_shopping_cart_content' => '<div class="widget_shopping_cart_content">' . $mini_cart . '</div>',
					)
				);
			}

			wp_send_json_success(
				array(
					'fragments' => $fragments,
					'cart_hash' => WC()->cart->get_cart_hash(),
				)
			);
		}

	} // end class

} // end class_exists
