<?php
/**
 * Shortcode handler for Product Display.
 *
 * @package Product_Display.
 */

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

/**
 * Class PRODDISP_Shortcode.
 *
 * This class handles the shortcode functionality for the plugin.
 */
class PRODDISP_Shortcode {
	/**
	 * The single instance of the class.
	 */
	protected static $_instance = null;

	/**
	 * Main Instance.
	 */
	public static function get_instance() {
		if ( is_null(self::$_instance) ) {
			self::$_instance = new self();
		}
		return self::$_instance;
	}

	/**
	 * Constructor.
	 */
	public function __construct() {
		add_shortcode('product_display', array( $this, 'render_shortcode' ));

		// Add AJAX handlers for pagination and filtering
		add_action('wp_ajax_proddisp_load_products', array( $this, 'ajax_load_products' ));
		add_action('wp_ajax_nopriv_proddisp_load_products', array( $this, 'ajax_load_products' ));
	}

	/**
	 * Render the product showcase shortcode.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string HTML output.
	 */
	public function render_shortcode( $atts ) {
		// Initialize atts array if it's not already.
		if ( ! is_array($atts) ) {
			$atts = array();
		}

		// Preserve the original attributes
		$original_atts = $atts;
		$original_id = isset($atts['id']) ? $atts['id'] : '';

		// Check if we're using a saved showcase by ID.
		if ( isset($atts['id']) && ! empty($atts['id']) ) {
			$saved_showcases = get_option('proddisp_saved_showcases', array());

			// Check if the showcase ID exists.
			if ( isset($saved_showcases[ $atts['id'] ]) ) {
				// Use the saved showcase settings.
				$saved_settings = $saved_showcases[ $atts['id'] ];

				// Convert saved settings to shortcode attributes format.
				$atts = $this->convert_saved_settings_to_atts($saved_settings);

				// Restore the original ID
				$atts['id'] = $original_id;

				// Apply original attributes as overrides
				foreach ( $original_atts as $key => $value ) {
					if ( $key !== 'id' && ! empty($value) ) {
						$atts[ $key ] = $value;
					}
				}
			} else {
				// Showcase with this ID doesn't exist anymore.
				return '<p>' . sprintf(__('Showcase ID "%s" not found. It may have been deleted.', 'product-display'), esc_html($atts['id'])) . '</p>';
			}
		}

		// Enqueue required assets.
		PRODDISP_Assets::get_instance()->enqueue_frontend_assets();

		// Parse attributes with defaults
		$atts = shortcode_atts(array(
			'id'              => '',
			'layout'          => 'grid',
			'proddisp_layout_mode' => 'basic-grid',
			'product_source'  => 'manual',
			'products'        => '',
			'category'        => '',
			'tag'             => '',
			'brand'           => '',
			'attribute'       => '',
			'attribute_terms' => '',
			'limit'           => 8,
			'columns'         => 4,
			'orderby'         => 'date',
			'order'           => 'DESC',
			'image_size'      => 'woocommerce_thumbnail',
			'show_title'      => 'yes',
			'show_price'      => 'yes',
			'show_rating'     => 'yes',
			'show_description' => 'no',
			'excerpt_length'  => 15,
			'show_addtocart'  => 'yes',
			'show_compare'    => 'no',
			'show_quickview'  => 'no',
			'show_wishlist'   => 'no',
			'action_position' => 'hover',
			'addtocart_display_mode' => 'icon_text',
			'addtocart_icon' => '',
			'compare_display_mode' => 'icon_only',
			'compare_icon' => '',
			'quickview_display_mode' => 'icon_only',
			'quickview_icon' => '',
			'wishlist_display_mode' => 'icon_only',
			'wishlist_icon' => '',
			// Container style attributes
			'container_background' => '',
			'container_padding' => '',
			'container_margin' => '',
			// Grid attributes
			'grid_gap' => '',
			'grid_width' => '',
			// Product style attributes
			'product_background' => '',
			'product_content_padding' => '',
			'product_title' => '',
			'product_title_hover_color' => '',
			'title_size' => '',
			'title_weight' => '',
			'description_color' => '',
			'desc_size' => '',
			'price_delete_color' => '',
			'price_color' => '',
			'price_size' => '',
			'price_weight' => '',
			'star_size' => '',
			'star_color' => '',
			'text_align' => '',
			// Border attributes
			'border_radius' => '',
			'border_style' => '',
			'border_width' => '',
			'border_color' => '',
			// Image attributes
			'product_image_width' => '',
			'product_image_height' => '',
			'image_aspect_ratio' => '',
			'image_border_radius' => '',
			// Badge attributes
			'product_badge_background' => '',
			'product_badge_font_color' => '',
			'product_badge_font_size' => '',
			'product_badge_font_weight' => '',
			'product_badge_text_align' => '',
			'product_badge_text_transform' => '',
			'product_badge_border_radius' => '',
			'product_badge_padding' => '',
			'product_badge_margin' => '',
			// Button attributes
			'button_border_radius' => '',
			'button_bg_color' => '',
			'button_text_color' => '',
			'button_hover_bg' => '',
			'button_hover_text_color' => '',
			'button_font_size' => '',
			'button_padding' => '',
			'button_margin' => '',
			'button_border' => '',
			'button_hover_border' => '',
			'button_animation' => '',
			// Product layout attributes
			'product_width' => '',
			'product_flex' => '',
			'product_content_background' => '',
			'product_content_margin' => '',
			'product_content_direction' => '',
			// Effects attributes
			'box_shadow' => '',
			'image_hover_effect' => '',
			'hover_effect' => '',
			'hover_transition' => '',
			'caption_hover_bg' => '',
			// AJAX and filtering options
			'enable_ajax' => 'no',
			'enable_filters' => 'no',
			'enable_pagination' => 'no',
			'pagination_per_page' => 4,
			// Slider specific attributes
			'autoplay' => 'yes',
			'arrows' => 'yes',
			'dots' => 'yes',
			'slide_speed' => 3000,
			// Custom CSS class
			'custom_class' => '',
		), $atts, 'product_display');

		// Conditionally enqueue FontAwesome based on shortcode settings
		PRODDISP_Assets::get_instance()->maybe_enqueue_fontawesome_for_shortcode($atts);

		// Handle URL parameters for non-AJAX filtering
		if ( 'no' === $atts['enable_ajax'] && 'yes' === $atts['enable_filters'] ) {

			// Check for category filter in URL
			if ( isset( $_GET['wcps_category'] ) && ! empty( $_GET['wcps_category'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Shortcode URL filter param, no nonce applicable.
				$atts['category'] = sanitize_text_field( wp_unslash( $_GET['wcps_category'] ) );
			}

			// Check for tag filter in URL
			if ( isset( $_GET['wcps_tag'] ) && ! empty( $_GET['wcps_tag'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Shortcode URL filter param, no nonce applicable.
				$atts['tag'] = sanitize_text_field( wp_unslash( $_GET['wcps_tag'] ) );
			}

			// Check for brand filter in URL
			if ( isset( $_GET['wcps_brand'] ) && ! empty( $_GET['wcps_brand'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Shortcode URL filter param, no nonce applicable.
				$atts['brand'] = sanitize_text_field( wp_unslash( $_GET['wcps_brand'] ) );
			}
		}

		// Handle pagination - check multiple sources for current page
		$current_page = $this->get_current_page();

		if ( 'yes' === $atts['enable_pagination'] ) {
			// Use pagination_per_page for query when pagination is enabled
			$original_limit = $atts['limit'];
			$atts['limit'] = intval($atts['pagination_per_page']);
			$atts['paged'] = $current_page;
		}

		// Get products.
		$products_data = $this->get_products($atts);
		$products = $products_data['products'];
		$query = $products_data['query'];

		if ( empty($products) ) {
			return '<p class="wcps-no-products">' . esc_html__('No products found.', 'product-display') . '</p>';
		}

		// Get layout class
		$layout_class = $this->get_layout_class($atts['layout'], $atts['proddisp_layout_mode']);

		if ( ! $layout_class ) {
			return '<p>' . esc_html__( 'Invalid layout type.', 'product-display' ) . '</p>';
		}

		// Get layout instance.
			$layout = new $layout_class($atts);

			// Generate unique ID for this showcase instance.
			$showcase_id = 'wcps-' . ( ! empty($atts['id']) ? $atts['id'] : uniqid() );
			$layout_mode_class = sanitize_html_class($atts['proddisp_layout_mode']);

			// Start output buffering.
			ob_start();

			// Generate CSS variables from attributes.
			$css_variables = $this->generate_css_variables($atts);
			$style_attr = ! empty($css_variables) ? ' style="' . esc_attr($css_variables) . '"' : '';

			// Build container classes.
			$container_classes = array(
				'wcps-container',
				'wcps-layout-' . $layout_mode_class,
				$showcase_id, // e.g. wcps-2 — mirrors the ID as a class for flexible CSS targeting
			);

			// Add custom class if provided.
			if ( ! empty($atts['custom_class']) && is_string($atts['custom_class']) ) {
				$custom_classes = explode(' ', $atts['custom_class']);
				foreach ( $custom_classes as $custom_class ) {
					$custom_class = trim($custom_class);
					if ( ! empty($custom_class) ) {
						$container_classes[] = sanitize_html_class($custom_class);
					}
				}
			}

			$container_class_attr = implode(' ', array_filter($container_classes));

			// Add wrapper with unique ID and CSS variables.
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $style_attr is already escaped via esc_attr().
			echo '<div id="' . esc_attr($showcase_id) . '" class="' . esc_attr($container_class_attr) . '"' . $style_attr . '>';

			// Add filters if enabled.
			if ( 'yes' === $atts['enable_filters'] ) {
				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped in render_filters() method.
				echo $this->render_filters($products, $atts);
			}

			// Render the layout.
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped in layout render() method.
			echo $layout->render($products);

			// Add pagination if enabled.
			if ( 'yes' === $atts['enable_pagination'] && isset($query) && $query->max_num_pages > 1 ) {
				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped in render_pagination() method.
				echo $this->render_pagination($query, $current_page);
			}

			echo '</div>';

			// Add AJAX script if enabled.
			if ( 'yes' === $atts['enable_ajax'] ) {
				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped in add_ajax_script() method.
				echo $this->add_ajax_script($showcase_id, $atts);
			} else {
				// Add basic pagination script for non-AJAX mode.
				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped in add_basic_pagination_script() method.
				echo $this->add_basic_pagination_script($showcase_id);
			}

			return ob_get_clean();
	}

	/**
	 * Get current page number from various sources.
	 *
	 * @return int Current page number.
	 */
	private function get_current_page() {
		$current_page = 1;

		// Check for custom pagination parameter first (most reliable for shortcodes)
		if ( isset($_GET['wcps_page']) && intval($_GET['wcps_page']) > 0 ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Pagination param in shortcode, no nonce applicable
			$current_page = absint( wp_unslash( $_GET['wcps_page'] ) );
		}
		// Check for page query var (works on static pages)
		elseif ( get_query_var('page') && intval(get_query_var('page')) > 0 ) {
			$current_page = get_query_var('page');
		}
		// Check for paged query var (works on archive pages)
		elseif ( get_query_var('paged') && intval(get_query_var('paged')) > 0 ) {
			$current_page = get_query_var('paged');
		}

		return max(1, intval($current_page));
	}

	/**
	 * Render pagination controls.
	 *
	 * @param WP_Query $query The query object.
	 * @param int      $current_page Current page number.
	 * @return string Pagination HTML.
	 */
	private function render_pagination( $query, $current_page ) {
		if ( $query->max_num_pages <= 1 ) {
			return '';
		}

		// Get current URL without pagination parameters
		global $wp;
		$current_url = home_url($wp->request);

		// Get current query string and remove pagination parameters
		$query_string = isset( $_SERVER['QUERY_STRING'] ) ? sanitize_text_field( wp_unslash( $_SERVER['QUERY_STRING'] ) ) : '';
		parse_str($query_string, $query_params);

		// Remove pagination parameters
		unset($query_params['paged'], $query_params['page'], $query_params['wcps_page']);

		// Rebuild query string
		$clean_query_string = http_build_query($query_params);

		// Build base URL
		$base_url = $current_url;
		if ( ! empty($clean_query_string) ) {
			$base_url .= '?' . $clean_query_string;
		}

		// Determine pagination parameter
		$paged_param = 'wcps_page';

		// Build pagination format
		$separator = empty($clean_query_string) ? '?' : '&';
		$format = $separator . $paged_param . '=%#%';

		$pagination = paginate_links(array(
			'base' => $base_url . '%_%',
			'format' => $format,
			'current' => max(1, $current_page),
			'total' => $query->max_num_pages,
			'prev_text' => '&larr; ' . esc_html__( 'Previous', 'product-display' ),
			'next_text' => esc_html__( 'Next', 'product-display' ) . ' &rarr;',
			'type' => 'list',
			'end_size' => 3,
			'mid_size' => 3,
		));

		if ( $pagination ) {
			return '<div class="wcps-pagination">' . $pagination . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- paginate_links() is a trusted WordPress core function.
		}

		return '';
	}

	/**
	 * Render filter controls.
	 *
	 * @param array $products Array of WooCommerce product objects.
	 * @param array $atts Shortcode attributes.
	 * @return string Filter HTML.
	 */
	private function render_filters( $products, $atts ) {
		$categories = array();

		// Get all available product categories instead of just from current products
		// This ensures filters work properly with pagination
		$all_categories = get_terms(array(
			'taxonomy' => 'product_cat',
			'hide_empty' => true,
			'orderby' => 'name',
			'order' => 'ASC',
		));

		if ( ! is_wp_error($all_categories) && ! empty($all_categories) ) {
			foreach ( $all_categories as $category ) {
				$categories[ $category->slug ] = $category->name;
			}
		}

		// Fallback: if no categories found via get_terms, collect from current products
		if ( empty($categories) ) {
			foreach ( $products as $product ) {
				$product_categories = wp_get_post_terms($product->get_id(), 'product_cat');
				foreach ( $product_categories as $category ) {
					if ( ! isset($categories[ $category->slug ]) ) {
						$categories[ $category->slug ] = $category->name;
					}
				}
			}
		}

		// No categories found
		if ( empty($categories) ) {
			return '';
		}

		// Get current filter from URL (for non-AJAX mode) or from attributes
		$current_filter = '';
		if ( 'no' === $atts['enable_ajax'] && isset( $_GET['wcps_category'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Shortcode URL filter param, no nonce applicable.
			$current_filter = sanitize_text_field( wp_unslash( $_GET['wcps_category'] ) );
		} elseif ( ! empty($atts['category']) ) {
			$current_filter = $atts['category'];
		}

		// Build filter navigation
		$output = '<div class="wcps-filters" style="display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-bottom: 20px;">';

		// "All" filter - active if no current filter
		$all_active_class = empty($current_filter) ? 'active' : '';
		$all_style = empty($current_filter) ?
			'padding: 8px 16px; background-color: #4a6cf7; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.3s ease; text-decoration: none;' :
			'padding: 8px 16px; background-color: #f5f5f5; color: #333333; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.3s ease; text-decoration: none;';

		$output .= '<a href="#" class="wcps-filter ' . sanitize_html_class( $all_active_class ) . '" data-filter-type="category" data-filter-value="" style="' . esc_attr( $all_style ) . '">' . esc_html__('All', 'product-display') . '</a>';

		foreach ( $categories as $slug => $name ) {
			// Check if this category is currently active
			$is_active = ( $current_filter === $slug );
			$active_class = $is_active ? 'active' : '';
			$style = $is_active ?
				'padding: 8px 16px; background-color: #4a6cf7; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.3s ease; text-decoration: none;' :
				'padding: 8px 16px; background-color: #f5f5f5; color: #333333; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.3s ease; text-decoration: none;';

			$output .= '<a href="#" class="wcps-filter ' . sanitize_html_class( $active_class ) . '" data-filter-type="category" data-filter-value="' . esc_attr($slug) . '" style="' . esc_attr( $style ) . '">' . esc_html($name) . '</a>';
		}

		$output .= '</div>';

		return $output;
	}

	/**
	 * Generate CSS variables from shortcode attributes
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string CSS variables as inline style string.
	 */
	private function generate_css_variables( $atts ) {
		$css_vars = array();

		// Container variables
		if ( ! empty($atts['container_background']) ) {
			$css_vars[] = '--wcps-container-background: ' . sanitize_hex_color($atts['container_background']);
		}
		if ( ! empty($atts['container_padding']) ) {
			$css_vars[] = '--wcps-container-padding: ' . sanitize_text_field($atts['container_padding']) . 'px';
		}
		if ( ! empty($atts['container_margin']) ) {
			$css_vars[] = '--wcps-container-margin: ' . sanitize_text_field($atts['container_margin']) . 'px';
		}

		// Grid variables
		if ( ! empty($atts['columns']) ) {
			$css_vars[] = '--wcps-columns: ' . intval($atts['columns']);
		}
		if ( ! empty($atts['grid_gap']) ) {
			$css_vars[] = '--wcps-grid-gap: ' . intval($atts['grid_gap']) . 'px';
		}
		if ( ! empty($atts['grid_width']) ) {
			$css_vars[] = '--wcps-grid-width: ' . sanitize_text_field($atts['grid_width']);
		}

		// Product variables
		if ( ! empty($atts['product_background']) ) {
			$css_vars[] = '--wcps-product-background: ' . sanitize_hex_color($atts['product_background']);
		}
		if ( ! empty($atts['product_content_padding']) ) {
			$css_vars[] = '--wcps-product-content-padding: ' . intval($atts['product_content_padding']) . 'px';
		}

		// Title variables
		if ( ! empty($atts['product_title']) ) {
			$css_vars[] = '--wcps-product-title: ' . sanitize_hex_color($atts['product_title']);
		}
		if ( ! empty($atts['product_title_hover_color']) ) {
			$css_vars[] = '--wcps-product-title-hover-color: ' . sanitize_hex_color($atts['product_title_hover_color']);
		}
		if ( ! empty($atts['title_size']) ) {
			$css_vars[] = '--wcps-title-size: ' . intval($atts['title_size']) . 'px';
		}
		if ( ! empty($atts['title_weight']) ) {
			$css_vars[] = '--wcps-title-weight: ' . sanitize_text_field($atts['title_weight']);
		}

		// Description variables
		if ( ! empty($atts['description_color']) ) {
			$css_vars[] = '--wcps-description-color: ' . sanitize_hex_color($atts['description_color']);
		}
		if ( ! empty($atts['desc_size']) ) {
			$css_vars[] = '--wcps-desc-size: ' . intval($atts['desc_size']) . 'px';
		}

		// Price variables
		if ( ! empty($atts['price_delete_color']) ) {
			$css_vars[] = '--wcps-price-delete-font-color: ' . sanitize_hex_color($atts['price_delete_color']);
		}
		if ( ! empty($atts['price_color']) ) {
			$css_vars[] = '--wcps-price-font-color: ' . sanitize_hex_color($atts['price_color']);
		}
		if ( ! empty($atts['price_size']) ) {
			$css_vars[] = '--wcps-price-font-size: ' . intval($atts['price_size']) . 'px';
		}
		if ( ! empty($atts['price_weight']) ) {
			$css_vars[] = '--wcps-price-font-weight: ' . sanitize_text_field($atts['price_weight']);
		}

		// Star rating variables
		if ( ! empty($atts['star_size']) ) {
			$css_vars[] = '--wcps-star-size: ' . intval($atts['star_size']) . 'px';
		}
		if ( ! empty($atts['star_color']) ) {
			$css_vars[] = '--wcps-star-color: ' . sanitize_hex_color($atts['star_color']);
		}

		// Text alignment
		if ( ! empty($atts['text_align']) ) {
			$css_vars[] = '--wcps-text-align: ' . sanitize_text_field($atts['text_align']);
		}

		// Border variables
		if ( ! empty($atts['border_radius']) ) {
			$css_vars[] = '--wcps-border-radius: ' . intval($atts['border_radius']) . 'px';
		}
		if ( ! empty($atts['border_style']) ) {
			$css_vars[] = '--wcps-border-style: ' . sanitize_text_field($atts['border_style']);
		}
		if ( ! empty($atts['border_width']) ) {
			$css_vars[] = '--wcps-border-width: ' . intval($atts['border_width']) . 'px';
		}

		// Image variables
		if ( ! empty($atts['product_image_width']) ) {
			$css_vars[] = '--wcps-product-image-width: ' . sanitize_text_field($atts['product_image_width']);
		}
		if ( ! empty($atts['product_image_height']) ) {
			$css_vars[] = '--wcps-product-image-height: ' . sanitize_text_field($atts['product_image_height']);
		}
		if ( ! empty($atts['image_aspect_ratio']) ) {
			$css_vars[] = '--wcps-image-aspect-ratio: ' . sanitize_text_field($atts['image_aspect_ratio']);
		}
		if ( ! empty($atts['image_border_radius']) ) {
			$css_vars[] = '--wcps-image-border-radius: ' . intval($atts['image_border_radius']) . 'px';
		}

		// Badge variables
		if ( ! empty($atts['product_badge_background']) ) {
			$css_vars[] = '--wcps-product-badge-background: ' . sanitize_text_field($atts['product_badge_background']);
		}
		if ( ! empty($atts['product_badge_font_color']) ) {
			$css_vars[] = '--wcps-product-badge-font-color: ' . sanitize_hex_color($atts['product_badge_font_color']);
		}
		if ( ! empty($atts['product_badge_font_size']) ) {
			$css_vars[] = '--wcps-product-badge-font-size: ' . intval($atts['product_badge_font_size']) . 'px';
		}
		if ( ! empty($atts['product_badge_font_weight']) ) {
			$css_vars[] = '--wcps-product-badge-font-weight: ' . sanitize_text_field($atts['product_badge_font_weight']);
		}
		if ( ! empty($atts['product_badge_text_align']) ) {
			$css_vars[] = '--wcps-product-badge-text-align: ' . sanitize_text_field($atts['product_badge_text_align']);
		}
		if ( ! empty($atts['product_badge_text_transform']) ) {
			$css_vars[] = '--wcps-product-badge-text-transform: ' . sanitize_text_field($atts['product_badge_text_transform']);
		}
		if ( ! empty($atts['product_badge_border_radius']) ) {
			$css_vars[] = '--wcps-product-badge-border-radius: ' . intval($atts['product_badge_border_radius']) . 'px';
		}
		if ( ! empty($atts['product_badge_padding']) ) {
			$css_vars[] = '--wcps-product-badge-padding: ' . sanitize_text_field($atts['product_badge_padding']) . 'px';
		}
		if ( ! empty($atts['product_badge_margin']) ) {
			$css_vars[] = '--wcps-product-badge-margin: ' . sanitize_text_field($atts['product_badge_margin']) . 'px';
		}

		// Button variables
		if ( ! empty($atts['button_border_radius']) ) {
			$css_vars[] = '--wcps-button-border-radius: ' . intval($atts['button_border_radius']) . 'px';
		}
		if ( ! empty($atts['button_bg_color']) ) {
			$css_vars[] = '--wcps-button-bg-color: ' . sanitize_hex_color($atts['button_bg_color']);
		}
		if ( ! empty($atts['button_text_color']) ) {
			$css_vars[] = '--wcps-button-text-color: ' . sanitize_hex_color($atts['button_text_color']);
		}
		if ( ! empty($atts['button_hover_bg']) ) {
			$css_vars[] = '--wcps-button-hover-bg: ' . sanitize_hex_color($atts['button_hover_bg']);
		}
		if ( ! empty($atts['button_hover_text_color']) ) {
			$css_vars[] = '--wcps-button-hover-text-color: ' . sanitize_hex_color($atts['button_hover_text_color']);
		}
		if ( ! empty($atts['button_font_size']) ) {
			$css_vars[] = '--wcps-button-font-size: ' . intval($atts['button_font_size']) . 'px';
		}
		if ( ! empty($atts['button_padding']) ) {
			$css_vars[] = '--wcps-button-padding: ' . sanitize_text_field($atts['button_padding']) . 'px';
		}
		if ( ! empty($atts['button_margin']) ) {
			$css_vars[] = '--wcps-button-margin: ' . sanitize_text_field($atts['button_margin']) . 'px';
		}
		if ( ! empty($atts['button_border']) ) {
			$css_vars[] = '--wcps-button-border: ' . sanitize_text_field($atts['button_border']);
		}
		if ( ! empty($atts['button_hover_border']) ) {
			$css_vars[] = '--wcps-button-hover-border: ' . sanitize_text_field($atts['button_hover_border']);
		}
		if ( ! empty($atts['button_animation']) ) {
			$css_vars[] = '--wcps-button-animation: ' . sanitize_text_field($atts['button_animation']);
		}

		// Product layout variables
		if ( isset($atts['product_width']) && $atts['product_width'] !== '' ) {
			$css_vars[] = '--wcps-product-width: ' . sanitize_text_field($atts['product_width']);
		}
		if ( isset($atts['product_flex']) && $atts['product_flex'] !== '' ) {
			$css_vars[] = '--wcps-product-flex: ' . sanitize_text_field($atts['product_flex']);
		}
		if ( isset($atts['product_content_background']) && $atts['product_content_background'] !== '' ) {
			$css_vars[] = '--wcps-product-content-background: ' . sanitize_hex_color($atts['product_content_background']);
		}
		if ( isset($atts['product_content_margin']) && $atts['product_content_margin'] !== '' ) {
			$css_vars[] = '--wcps-product-content-margin: ' . sanitize_text_field($atts['product_content_margin']) . 'px';
		}
		if ( isset($atts['product_content_direction']) && $atts['product_content_direction'] !== '' ) {
			$css_vars[] = '--wcps-product-content-direction: ' . sanitize_text_field($atts['product_content_direction']);
		}

		// Effects variables
		if ( ! empty($atts['box_shadow']) ) {
			$css_vars[] = '--wcps-box-shadow: ' . sanitize_text_field($atts['box_shadow']);
		}
		if ( ! empty($atts['image_hover_effect']) ) {
			$css_vars[] = '--wcps-image-hover-effect: ' . sanitize_text_field($atts['image_hover_effect']);
		}
		if ( ! empty($atts['hover_effect']) ) {
			$css_vars[] = '--wcps-hover-effect: ' . sanitize_text_field($atts['hover_effect']);
		}
		if ( ! empty($atts['hover_transition']) ) {
			$css_vars[] = '--wcps-hover-transition: ' . floatval($atts['hover_transition']) . 's';
		}
		if ( ! empty($atts['caption_hover_bg']) ) {
			$css_vars[] = '--wcps-caption-hover-bg: ' . sanitize_text_field($atts['caption_hover_bg']);
		}

		// Border color variable
		if ( isset($atts['border_color']) && $atts['border_color'] !== '' ) {
			$css_vars[] = '--wcps-border-color: ' . sanitize_hex_color($atts['border_color']);
		}

		// Action icon variables
		if ( ! empty($atts['compare_icon']) ) {
			$css_vars[] = '--wcps-compare-icon: ' . sanitize_text_field($atts['compare_icon']);
		}
		if ( ! empty($atts['wishlist_icon']) ) {
			$css_vars[] = '--wcps-wishlist-icon: ' . sanitize_text_field($atts['wishlist_icon']);
		}
		if ( ! empty($atts['quickview_icon']) ) {
			$css_vars[] = '--wcps-quickview-icon: ' . sanitize_text_field($atts['quickview_icon']);
		}
		if ( ! empty($atts['addtocart_icon']) ) {
			$css_vars[] = '--wcps-addtocart-icon: ' . sanitize_text_field($atts['addtocart_icon']);
		}

		return ! empty($css_vars) ? implode('; ', $css_vars) : '';
	}

	/**
	 * Get products based on shortcode attributes.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return array Array with products and query info.
	 */
	private function get_products( $atts ) {
		$args = array(
			'post_type'      => 'product',
			'posts_per_page' => intval($atts['limit']),
			'orderby'        => $atts['orderby'],
			'order'          => $atts['order'],
			'post_status'    => 'publish',
		);

		// Add pagination if specified
		if ( isset($atts['paged']) && $atts['paged'] > 1 ) {
			$args['paged'] = intval($atts['paged']);
		}

		// Filter by specific products if provided.
		if ( ! empty($atts['products']) ) {
			$product_ids = array_map('intval', explode(',', $atts['products']));
			if ( ! empty($product_ids) ) {
				$args['post__in'] = $product_ids;
				$args['orderby'] = 'post__in';
			}
		}
		// Filter by category if provided.
		elseif ( ! empty($atts['category']) ) {
			$category_ids = array_map('intval', explode(',', $atts['category']));
			if ( ! empty($category_ids) ) {
				$args['tax_query'] = array(
					array(
						'taxonomy' => 'product_cat',
						'field'    => 'term_id',
						'terms'    => $category_ids,
					),
				);
			}
		}
		// Filter by tag if provided
		elseif ( ! empty($atts['tag']) ) {
			$tag_ids = array_map('intval', explode(',', $atts['tag']));
			if ( ! empty($tag_ids) ) {
				$args['tax_query'] = array(
					array(
						'taxonomy' => 'product_tag',
						'field'    => 'term_id',
						'terms'    => $tag_ids,
					),
				);
			}
		}

		// Execute query
		$query = new WP_Query($args);
		$products = array();

		if ( $query->have_posts() ) {
			while ( $query->have_posts() ) {
				$query->the_post();
				$product = wc_get_product(get_the_ID());
				if ( $product ) {
					$products[] = $product;
				}
			}
			wp_reset_postdata();
		}

		// If no products found and no specific filters applied, get sample products for preview
		if ( empty($products) && empty($atts['products']) && empty($atts['category']) && empty($atts['tag']) ) {
			$sample_args = array(
				'post_type'      => 'product',
				'posts_per_page' => intval($atts['limit']), // Use the current limit (which might be pagination_per_page)
				'orderby'        => 'date', // Use date instead of rand for consistent pagination
				'order'          => 'DESC',
				'post_status'    => 'publish',
			);

			// Add pagination if specified
			if ( isset($atts['paged']) && $atts['paged'] > 1 ) {
				$sample_args['paged'] = intval($atts['paged']);
			}

			$sample_query = new WP_Query($sample_args);
			if ( $sample_query->have_posts() ) {
				while ( $sample_query->have_posts() ) {
					$sample_query->the_post();
					$product = wc_get_product(get_the_ID());
					if ( $product ) {
						$products[] = $product;
					}
				}
				wp_reset_postdata();
				// Use sample query for pagination
				$query = $sample_query;
			}
		}

		return array(
			'products' => $products,
			'query' => $query,
		);
	}

	/**
	 * Get the appropriate layout class based on layout type and mode.
	 *
	 * @param string $layout_type The selected layout type.
	 * @param string $layout_mode The selected layout mode.
	 * @return string|false The class name or false if invalid.
	 */
	private function get_layout_class( $layout_type, $layout_mode = 'basic' ) {
		// Define available modes for each layout type.
		$layout_classes = array(
			'grid' => array(
				'basic-grid'    => 'PRODDISP_Grid',
				'basic-grid-7'  => 'PRODDISP_Grid',
				'basic-grid-8'  => 'PRODDISP_Grid',
				'basic-grid-11' => 'PRODDISP_Grid',
				'basic-grid-2'  => 'PRODDISP_Grid',
				'basic-grid-3'  => 'PRODDISP_Grid',
				'basic-grid-4'  => 'PRODDISP_Grid',
				'basic-grid-5'  => 'PRODDISP_Grid',
				'basic-grid-6'  => 'PRODDISP_Grid',
				'basic-grid-9'  => 'PRODDISP_Grid',
				'basic-grid-10' => 'PRODDISP_Grid',
				'basic-grid-12' => 'PRODDISP_Grid',
				'default'       => 'PRODDISP_Grid',
			),
			'card_grid' => array(
				'card-grid'    => 'PRODDISP_Card',
				'card-grid-2'  => 'PRODDISP_Card',
				'card-grid-3'  => 'PRODDISP_Card',
				'default'      => 'PRODDISP_Card',
			),
			'slider' => array(
				'slider'       => 'PRODDISP_Slider',
				'slider-2'     => 'PRODDISP_Slider',
				'slider-3'     => 'PRODDISP_Slider',
				'slider-4'     => 'PRODDISP_Slider',
				'slider-5'     => 'PRODDISP_Slider',
				'slider-6'     => 'PRODDISP_Slider',
				'default'      => 'PRODDISP_Slider',
			),
			'masonry_grid' => array(
				'masonry-grid'   => 'PRODDISP_Masonry',
				'masonry-grid-2' => 'PRODDISP_Masonry',
				'masonry-grid-3' => 'PRODDISP_Masonry',
				'default'        => 'PRODDISP_Masonry',
			),
			'gallery' => array(
				'gallery'   => 'PRODDISP_Gallery',
				'gallery-2' => 'PRODDISP_Gallery',
				'gallery-3' => 'PRODDISP_Gallery',
				'default'   => 'PRODDISP_Gallery',
			),
			'flip' => array(
				'flip-layout'   => 'PRODDISP_Flip',
				'flip-layout-2' => 'PRODDISP_Flip',
				'flip-layout-3' => 'PRODDISP_Flip',
				'flip-layout-4' => 'PRODDISP_Flip',
				'flip-layout-5' => 'PRODDISP_Flip',
				'default'       => 'PRODDISP_Flip',
			),
			'table' => array(
				'table'   => 'PRODDISP_Table',
				'table-2' => 'PRODDISP_Table',
				'table-3' => 'PRODDISP_Table',
				'default' => 'PRODDISP_Table',
			),

			'showcase' => array(
				'showcase'         => $this->get_showcase_class(),
				'showcase-2'       => $this->get_showcase_class(),
				'showcase-3'       => $this->get_showcase_class(),
				'default'          => $this->get_showcase_class(),
			),
			'category_tabs' => array(
				'category_tabs'   => 'PRODDISP_Category_Tabs',
				'category_tabs_2' => 'PRODDISP_Category_Tabs',
				'category_tabs_3' => 'PRODDISP_Category_Tabs',
				'default'         => 'PRODDISP_Category_Tabs',
			),
			'list' => array(
				'list-layout'   => 'PRODDISP_List',
				'list-layout-2' => 'PRODDISP_List',
				'list-layout-3' => 'PRODDISP_List',
				'default'       => 'PRODDISP_List',
			),
			'cta' => array(
				'cta-layout'   => 'PRODDISP_CTA',
				'cta-layout-2' => 'PRODDISP_CTA',
				'cta-layout-3' => 'PRODDISP_CTA',
				'cta-layout-4' => 'PRODDISP_CTA',
				'cta-layout-5' => 'PRODDISP_CTA',
				'cta-layout-6' => 'PRODDISP_CTA',
				'default'      => 'PRODDISP_CTA',
			),
			'caption' => array(
				'blinds-vertical'        => 'PRODDISP_Caption',
				'blocks-zoom-top-left'   => 'PRODDISP_Caption',
				// Pro
				'book-open-horizontal'   => 'PRODDISP_Caption',
				'border-reveal-top-left' => 'PRODDISP_Caption',
				'bounce-out-right'       => 'PRODDISP_Caption',
				'circle-top-left'        => 'PRODDISP_Caption',
				'cube-left'              => 'PRODDISP_Caption',
				'swiper-slide'           => 'PRODDISP_Caption',
				'liquid-morph'           => 'PRODDISP_Caption',
				'neon-glow'              => 'PRODDISP_Caption',
				'origami-fold'           => 'PRODDISP_Caption',
				'particle-burst'         => 'PRODDISP_Caption',
				'hologram'               => 'PRODDISP_Caption',
				'glass-shatter'          => 'PRODDISP_Caption',
				'magnetic-pull'          => 'PRODDISP_Caption',
				'quantum-tunnel'         => 'PRODDISP_Caption',
				'fire-ignition'          => 'PRODDISP_Caption',
				'matrix-rain'            => 'PRODDISP_Caption',
				'default'                => 'PRODDISP_Caption',
			),
		);

		// Check if the layout type exists.
		if ( ! isset($layout_classes[ $layout_type ]) ) {
			return false;
		}

		// Extract mode from layout_mode.
		$mode = $layout_mode;

		// Check if the specific mode exists for this layout type.
		if ( isset($layout_classes[ $layout_type ][ $mode ]) ) {
			return $layout_classes[ $layout_type ][ $mode ];
		}

		// If the specific mode doesn't exist, return the default for this layout type.
		return $layout_classes[ $layout_type ]['default'];
	}

	/**
	 * Convert saved settings to shortcode attributes format.
	 *
	 * @param array $settings Saved showcase settings.
	 * @return array Formatted shortcode attributes.
	 */
	private function convert_saved_settings_to_atts( $settings ) {
		$atts = array();

		// Map the form fields to shortcode attributes.
		$mapping = array(
			'layout' => 'layout',
			'proddisp_layout_mode' => 'proddisp_layout_mode',
			'product_source' => 'product_source',
			'limit' => 'limit',
			'columns' => 'columns',
			'orderby' => 'orderby',
			'order' => 'order',
			'show_compare' => 'show_compare',
			'compare_display_mode' => 'compare_display_mode',
			'compare_icon' => 'compare_icon',
			'show_wishlist' => 'show_wishlist',
			'wishlist_display_mode' => 'wishlist_display_mode',
			'wishlist_icon' => 'wishlist_icon',
			'show_quickview' => 'show_quickview',
			'quickview_display_mode' => 'quickview_display_mode',
			'quickview_icon' => 'quickview_icon',
			'show_addtocart' => 'show_addtocart',
			'addtocart_display_mode' => 'addtocart_display_mode',
			'addtocart_icon' => 'addtocart_icon',
			'action_position' => 'action_position',
			'image_size' => 'image_size',
			'show_title' => 'show_title',
			'show_price' => 'show_price',
			'show_rating' => 'show_rating',
			'show_description' => 'show_description',
			'excerpt_length' => 'excerpt_length',
			'autoplay' => 'autoplay',
			'arrows' => 'arrows',
			'dots' => 'dots',
			'slide_speed' => 'slide_speed',
			// AJAX and pagination settings
			'enable_ajax' => 'enable_ajax',
			'enable_filters' => 'enable_filters',
			'enable_pagination' => 'enable_pagination',
			'pagination_per_page' => 'pagination_per_page',
			// Container style attributes
			'container_background' => 'container_background',
			'container_padding' => 'container_padding',
			'container_margin' => 'container_margin',
			// Grid attributes
			'grid_gap' => 'grid_gap',
			'grid_width' => 'grid_width',
			// Product style attributes
			'product_background' => 'product_background',
			'product_content_padding' => 'product_content_padding',
			'product_title' => 'product_title',
			'product_title_hover_color' => 'product_title_hover_color',
			'title_size' => 'title_size',
			'title_weight' => 'title_weight',
			'description_color' => 'description_color',
			'desc_size' => 'desc_size',
			'price_delete_color' => 'price_delete_color',
			'price_color' => 'price_color',
			'price_size' => 'price_size',
			'price_weight' => 'price_weight',
			'star_size' => 'star_size',
			'star_color' => 'star_color',
			'text_align' => 'text_align',
			// Border attributes
			'border_radius' => 'border_radius',
			'border_style' => 'border_style',
			'border_width' => 'border_width',
			'border_color' => 'border_color',
			// Image attributes
			'product_image_width' => 'product_image_width',
			'product_image_height' => 'product_image_height',
			'image_aspect_ratio' => 'image_aspect_ratio',
			'image_border_radius' => 'image_border_radius',
			// Badge attributes
			'product_badge_background' => 'product_badge_background',
			'product_badge_font_color' => 'product_badge_font_color',
			'product_badge_font_size' => 'product_badge_font_size',
			'product_badge_font_weight' => 'product_badge_font_weight',
			'product_badge_text_align' => 'product_badge_text_align',
			'product_badge_text_transform' => 'product_badge_text_transform',
			'product_badge_border_radius' => 'product_badge_border_radius',
			'product_badge_padding' => 'product_badge_padding',
			'product_badge_margin' => 'product_badge_margin',
			// Button attributes
			'button_border_radius' => 'button_border_radius',
			'button_bg_color' => 'button_bg_color',
			'button_text_color' => 'button_text_color',
			'button_hover_bg' => 'button_hover_bg',
			'button_hover_text_color' => 'button_hover_text_color',
			'button_font_size' => 'button_font_size',
			'button_padding' => 'button_padding',
			'button_margin' => 'button_margin',
			'button_border' => 'button_border',
			'button_hover_border' => 'button_hover_border',
			'button_animation' => 'button_animation',
			// Product layout attributes
			'product_width' => 'product_width',
			'product_flex' => 'product_flex',
			'product_content_background' => 'product_content_background',
			'product_content_margin' => 'product_content_margin',
			'product_content_direction' => 'product_content_direction',
			// Effects attributes
			'box_shadow' => 'box_shadow',
			'image_hover_effect' => 'image_hover_effect',
			'hover_effect' => 'hover_effect',
			'hover_transition' => 'hover_transition',
			'caption_hover_bg' => 'caption_hover_bg',
			// Custom CSS class
			'custom_class' => 'custom_class',
		);

		foreach ( $mapping as $form_field => $att_name ) {
			if ( isset($settings[ $form_field ]) ) {
				$atts[ $att_name ] = $settings[ $form_field ];
			}
		}

		// Get the product_source to determine which fields to prioritize
		$product_source = isset($settings['product_source']) ? $settings['product_source'] : 'specific';

		// Handle array fields based on product_source priority

		// Handle specific products
		if ( isset($settings['products']) && is_array($settings['products']) && ! empty($settings['products']) ) {
			$atts['products'] = implode(',', $settings['products']);
		}

		// Handle categories
		if ( isset($settings['category']) && is_array($settings['category']) && ! empty($settings['category']) ) {
			$atts['category'] = implode(',', $settings['category']);
		}

		// Handle tags
		if ( isset($settings['tag']) && is_array($settings['tag']) && ! empty($settings['tag']) ) {
			$atts['tag'] = implode(',', $settings['tag']);
		}

		// Handle brands
		if ( isset($settings['brand']) && is_array($settings['brand']) && ! empty($settings['brand']) ) {
			$atts['brand'] = implode(',', $settings['brand']);
		}

		// Handle attribute taxonomy
		if ( isset($settings['attribute']) && ! empty($settings['attribute']) ) {
			$atts['attribute'] = $settings['attribute'];
		}

		// Handle attribute terms
		if ( isset($settings['attribute_terms']) && is_array($settings['attribute_terms']) && ! empty($settings['attribute_terms']) ) {
			$atts['attribute_terms'] = implode(',', $settings['attribute_terms']);
		}

		// Clear conflicting fields based on product_source to prevent conflicts
		switch ( $product_source ) {
			case 'specific':
				// When specific selection, only keep products, clear taxonomy fields
				if ( ! empty($atts['products']) ) {
					unset($atts['category']);
					unset($atts['tag']);
					unset($atts['brand']);
					unset($atts['attribute']);
					unset($atts['attribute_terms']);
				}
				break;

			case 'category':
				// When category selection, only keep category, clear others
				if ( ! empty($atts['category']) ) {
					unset($atts['products']);
					unset($atts['tag']);
					unset($atts['brand']);
					unset($atts['attribute']);
					unset($atts['attribute_terms']);
				}
				break;

			case 'tag':
				// When tag selection, only keep tag, clear others
				if ( ! empty($atts['tag']) ) {
					unset($atts['products']);
					unset($atts['category']);
					unset($atts['brand']);
					unset($atts['attribute']);
					unset($atts['attribute_terms']);
				}
				break;

			case 'brand':
				// When brand selection, only keep brand, clear others
				if ( ! empty($atts['brand']) ) {
					unset($atts['products']);
					unset($atts['category']);
					unset($atts['tag']);
					unset($atts['attribute']);
					unset($atts['attribute_terms']);
				}
				break;

			case 'attribute':
				// When attribute selection, only keep attribute fields, clear others
				if ( ! empty($atts['attribute']) ) {
					unset($atts['products']);
					unset($atts['category']);
					unset($atts['tag']);
					unset($atts['brand']);
				}
				break;
		}

		return $atts;
	}

	/**
	 * Get the appropriate showcase class name based on PRO availability
	 *
	 * @return string The showcase class name to use
	 */
	private function get_showcase_class() {
		return PRODDISP_Loader::is_pro_active() ? 'PRODDISP_PRO_Showcase' : 'PRODDISP_Showcase';
	}

	/**
	 * AJAX handler for loading products with pagination and filtering.
	 */
	public function ajax_load_products() {
		// Verify nonce.
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wcps-nonce' ) ) {
			wp_send_json_error([
				'message' => esc_html__( 'Invalid action', 'product-display' ),
			]);
		}

		// Get settings from request.
		$settings = isset($_POST['settings']) ? array_map('sanitize_text_field', wp_unslash($_POST['settings'])) : array();

		// Sanitize settings.
		$sanitized_settings = array();
		foreach ( $settings as $key => $value ) {
			if ( is_array($value) ) {
				$sanitized_settings[ $key ] = array_map('sanitize_text_field', $value);
			} else {
				$sanitized_settings[ $key ] = sanitize_text_field($value);
			}
		}

		// Prepare query args.
		$posts_per_page = isset($sanitized_settings['pagination_per_page']) ? absint($sanitized_settings['pagination_per_page']) :
						 ( isset($sanitized_settings['limit']) ? absint($sanitized_settings['limit']) : 10 );

		$args = array(
			'post_type'      => 'product',
			'posts_per_page' => $posts_per_page,
			'paged'          => isset($sanitized_settings['paged']) ? absint($sanitized_settings['paged']) : 1,
			'post_status'    => 'publish',
		);

		// Handle orderby.
		if ( isset($sanitized_settings['orderby']) ) {
			if ( $sanitized_settings['orderby'] === 'price' ) {
				$args['meta_key'] = '_price';
				$args['orderby'] = 'meta_value_num';
				$args['order'] = 'ASC';
			} else if ( $sanitized_settings['orderby'] === 'price-desc' ) {
				$args['meta_key'] = '_price';
				$args['orderby'] = 'meta_value_num';
				$args['order'] = 'DESC';
			} else if ( $sanitized_settings['orderby'] === 'rating' ) {
				$args['meta_key'] = '_wc_average_rating';
				$args['orderby'] = 'meta_value_num';
				$args['order'] = 'DESC';
			} else if ( $sanitized_settings['orderby'] === 'popularity' ) {
				$args['meta_key'] = 'total_sales';
				$args['orderby'] = 'meta_value_num';
				$args['order'] = 'DESC';
			} else {
				$args['orderby'] = $sanitized_settings['orderby'];
				$args['order'] = isset($sanitized_settings['order']) ? $sanitized_settings['order'] : 'DESC';
			}
		}

		// Initialize tax_query array
		$tax_query = array();

		// Handle products.
		if ( ! empty($sanitized_settings['products']) ) {
			$product_ids = array();

			if ( is_array($sanitized_settings['products']) ) {
				$product_ids = array_map('intval', $sanitized_settings['products']);
			} else {
				$product_ids = array_map('intval', explode(',', $sanitized_settings['products']));
			}

			if ( ! empty($product_ids) ) {
				$args['post__in'] = $product_ids;
			}
		}

		// Handle category filtering - FIXED
		if ( ! empty($sanitized_settings['category']) ) {
			$category_terms = array();

			if ( is_array($sanitized_settings['category']) ) {
				$category_terms = $sanitized_settings['category'];
			} else {
				$category_terms = explode(',', $sanitized_settings['category']);
			}

			// Filter out empty values
			$category_terms = array_filter($category_terms);

			if ( ! empty($category_terms) ) {
				// Check if we have numeric IDs or slugs
				$first_term = reset($category_terms);
				$field = is_numeric($first_term) ? 'term_id' : 'slug';

				// Convert to integers if numeric
				if ( $field === 'term_id' ) {
					$category_terms = array_map('intval', $category_terms);
				}

				$tax_query[] = array(
					'taxonomy' => 'product_cat',
					'field'    => $field,
					'terms'    => $category_terms,
				);
			}
		}

		// Handle tags
		if ( ! empty($sanitized_settings['tag']) ) {
			$tag_ids = array();

			if ( is_array($sanitized_settings['tag']) ) {
				$tag_ids = array_map('intval', $sanitized_settings['tag']);
			} else if ( is_numeric($sanitized_settings['tag']) ) {
				$tag_ids = array( intval($sanitized_settings['tag']) );
			} else {
				$tag_ids = array_map('intval', explode(',', $sanitized_settings['tag']));
			}

			if ( ! empty($tag_ids) ) {
				$tax_query[] = array(
					'taxonomy' => 'product_tag',
					'field'    => 'term_id',
					'terms'    => $tag_ids,
				);
			}
		}

		// Handle brands
		if ( ! empty($sanitized_settings['brand']) ) {
			$brand_ids = array();

			if ( is_array($sanitized_settings['brand']) ) {
				$brand_ids = array_map('intval', $sanitized_settings['brand']);
			} else if ( is_numeric($sanitized_settings['brand']) ) {
				$brand_ids = array( intval($sanitized_settings['brand']) );
			} else {
				$brand_ids = array_map('intval', explode(',', $sanitized_settings['brand']));
			}

			if ( ! empty($brand_ids) ) {
				// Check which brand taxonomy is active
				$brand_taxonomy = taxonomy_exists('product_brand') ? 'product_brand' :
								( taxonomy_exists('pwb-brand') ? 'pwb-brand' :
								( taxonomy_exists('yith_product_brand') ? 'yith_product_brand' : '' ) );

				if ( ! empty($brand_taxonomy) ) {
					$tax_query[] = array(
						'taxonomy' => $brand_taxonomy,
						'field'    => 'term_id',
						'terms'    => $brand_ids,
					);
				}
			}
		}

		// Handle attributes
		if ( ! empty($sanitized_settings['attribute']) && ! empty($sanitized_settings['attribute_terms']) ) {
			$attribute_terms = array();

			if ( is_array($sanitized_settings['attribute_terms']) ) {
				$attribute_terms = array_map('intval', $sanitized_settings['attribute_terms']);
			} else if ( is_numeric($sanitized_settings['attribute_terms']) ) {
				$attribute_terms = array( intval($sanitized_settings['attribute_terms']) );
			} else {
				$attribute_terms = array_map('intval', explode(',', $sanitized_settings['attribute_terms']));
			}

			if ( ! empty($attribute_terms) ) {
				$tax_query[] = array(
					'taxonomy' => $sanitized_settings['attribute'],
					'field'    => 'term_id',
					'terms'    => $attribute_terms,
				);
			}
		}

		// Add tax_query to args if we have any
		if ( ! empty($tax_query) ) {
			$args['tax_query'] = $tax_query;

			// If we have multiple taxonomies, set the relation
			if ( count($tax_query) > 1 ) {
				$args['tax_query']['relation'] = 'AND';
			}
		}

		// Execute query
		$query = new WP_Query($args);
		$products = array();

		if ( $query->have_posts() ) {
			while ( $query->have_posts() ) {
				$query->the_post();
				$product = wc_get_product(get_the_ID());
				if ( $product ) {
					$products[] = $product;
				}
			}
			wp_reset_postdata();
		}

		// Allow empty results for filtering - don't error out
		// if ( empty($products) ) {
		// wp_send_json_error([
		// 'message' => __( 'No products found', 'product-display' ),
		// ]);
		// }

		// Get layout class
		$layout_class = $this->get_layout_class($sanitized_settings['layout'], $sanitized_settings['proddisp_layout_mode']);

		if ( ! $layout_class ) {
			wp_send_json_error([
				'message' => esc_html__( 'Invalid layout type', 'product-display' ),
			]);
		}

		// Get layout instance
		$layout = new $layout_class($sanitized_settings);

		// Generate products HTML
		$products_html = empty($products) ? '<p class="wcps-no-products">' . esc_html__( 'No products found.', 'product-display' ) . '</p>' : $layout->render($products);

		// Generate pagination HTML
		$pagination_html = '';
		if ( 'yes' === $sanitized_settings['enable_pagination'] && $query->max_num_pages > 1 ) {
			$current_page = isset($sanitized_settings['paged']) ? intval($sanitized_settings['paged']) : 1;
			$pagination_html = $this->render_pagination($query, $current_page);
		}

		// Debug info (only for admins)
		$debug_info = array();
		if ( current_user_can('manage_options') && isset($_GET['debug_wcps']) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Admin-only debug utility, capability check is sufficient
			$debug_info = array(
				'query_args' => $args,
				'settings' => $sanitized_settings,
				'products_count' => count($products),
				'found_posts' => $query->found_posts,
				'max_pages' => $query->max_num_pages,
			);
		}

		wp_send_json_success([
			'html' => $products_html,
			'pagination' => $pagination_html,
			'found_posts' => $query->found_posts,
			'max_pages' => $query->max_num_pages,
			'debug' => $debug_info,
		]);
	}

	/**
	 * Add AJAX script for pagination and filtering.
	 *
	 * @param string $container_id Container ID.
	 * @param array  $atts Shortcode attributes.
	 * @return string AJAX script HTML.
	 */
	private function add_ajax_script( $container_id, $atts ) {
		ob_start();
		?>
		<script type="text/javascript">
		jQuery(document).ready(function($) {
			var container = $('#<?php echo esc_js($container_id); ?>');
			var settings = <?php echo wp_json_encode($atts); ?>;
			
			// Handle pagination clicks
			<?php if ( 'yes' === $atts['enable_pagination'] ) : ?>
			container.on('click', '.wcps-pagination a', function(e) {
				e.preventDefault();
				var url = $(this).attr('href');
				var page = 1;
				
				// Extract page number from URL - try multiple patterns
				var matches = url.match(/wcps_page=(\d+)/) || url.match(/paged=(\d+)/) || url.match(/page=(\d+)/) || url.match(/page\/(\d+)/);
				if (matches) {
					page = parseInt(matches[1]);
				} else if ($(this).hasClass('next')) {
					page = parseInt(settings.paged || 1) + 1;
				} else if ($(this).hasClass('prev')) {
					page = Math.max(1, parseInt(settings.paged || 1) - 1);
				}
				
				loadProducts(page);
			});
			<?php endif; ?>
			
			// Handle filter clicks
			<?php if ( 'yes' === $atts['enable_filters'] ) : ?>
			container.on('click', '.wcps-filter', function(e) {
				e.preventDefault();
				var filterType = $(this).data('filter-type');
				var filterValue = $(this).data('filter-value');
				
				// Update settings with filter
				if (filterValue === '' || filterValue === 'all') {
					// "All" filter - clear the filter
					delete settings[filterType];
				} else {
					settings[filterType] = filterValue;
				}
				
				// Update active filter
				container.find('.wcps-filter[data-filter-type="' + filterType + '"]').removeClass('active');
				$(this).addClass('active');
				
				// Reset to page 1 when filtering
				loadProducts(1);
			});
			<?php endif; ?>
			
			function loadProducts(page) {
				// Show loading
				container.addClass('wcps-loading');
				
				// Update page in settings
				settings.paged = page;
				
				$.ajax({
					url: proddisp_params.ajax_url,
					type: 'POST',
					data: {
						action: 'proddisp_load_products',
						nonce: proddisp_params.nonce,
						settings: settings
					},
					success: function(response) {
						if (response.success) {
							// Find the products container - try multiple selectors
							var productsContainer = container.find('.wcps-products-container, .wcps-grid-container, .wcps-slider-container, .wcps-products, .products');
							if (productsContainer.length === 0) {
								// If no specific container found, look for the main content area
								productsContainer = container.find('.wcps-container > div:first-child');
							}
							
							if (productsContainer.length > 0) {
								productsContainer.html(response.data.html);
							} else {
								// Fallback: replace entire container content except filters
								var filtersHtml = container.find('.wcps-filters').prop('outerHTML') || '';
								container.html(filtersHtml + response.data.html + (response.data.pagination || ''));
							}
							
							// Update pagination
							if (response.data.pagination) {
								var paginationContainer = container.find('.wcps-pagination');
								if (paginationContainer.length > 0) {
									paginationContainer.replaceWith(response.data.pagination);
								} else {
									// If no pagination container exists, append it
									container.append(response.data.pagination);
								}
							}
							
							// Reinitialize features
							if (typeof PRODDISP_Features !== 'undefined') {
								PRODDISP_Features.init();
							}
							
							// Reinitialize layout specific features
							if (typeof WCPS !== 'undefined') {
								if (settings.layout === 'slider') {
									WCPS.initSliderLayout();
								} else if (settings.layout === 'gallery') {
									WCPS.initGalleryLayout();
								}
							}
						} else {
							console.error('AJAX Error:', response.data.message);
						}
						
						// Remove loading
						container.removeClass('wcps-loading');
					},
					error: function(xhr, status, error) {
						console.error('AJAX Request Failed:', error);
						// Remove loading
						container.removeClass('wcps-loading');
					}
				});
			}
		});
		</script>
		<?php
		return ob_get_clean();
	}

	/**
	 * Add basic pagination script for non-AJAX mode.
	 *
	 * @param string $container_id Container ID.
	 * @return string Basic pagination script HTML.
	 */
	private function add_basic_pagination_script( $container_id ) {
		ob_start();
		?>
		<script type="text/javascript">
		jQuery(document).ready(function($) {
			var container = $('#<?php echo esc_js($container_id); ?>');
			
			// Handle filter clicks for non-AJAX mode
			container.on('click', '.wcps-filter', function(e) {
				e.preventDefault();
				var filterType = $(this).data('filter-type');
				var filterValue = $(this).data('filter-value');
				
				// Build URL with filter parameters
				var url = new URL(window.location.href);
				
				if (filterValue === '' || filterValue === 'all') {
					// "All" filter - remove the filter parameter
					url.searchParams.delete('wcps_' + filterType);
				} else {
					// Set the filter parameter
					url.searchParams.set('wcps_' + filterType, filterValue);
				}
				
				// Remove page parameter when filtering (reset to page 1)
				url.searchParams.delete('wcps_page');
				
				// Redirect to the new URL
				window.location.href = url.toString();
			});
			
			// Smooth scroll to container when pagination is clicked
			container.on('click', '.wcps-pagination a', function() {
				// Small delay to allow page load, then scroll
				setTimeout(function() {
					$('html, body').animate({
						scrollTop: container.offset().top - 100
					}, 500);
				}, 100);
			});
		});
		</script>
		<?php
		return ob_get_clean();
	}
}
