<?php
/**
 * GGM Commerce Wishlist Class
 *
 * Handles multiple wishlists functionality including storage, retrieval, and management.
 * Supports both logged-in users (stored in database) and guests (stored in session/cookie).
 * Logged-in users can have multiple named wishlists; guests have a single default list.
 *
 * @package GGM_Commerce
 */

defined( 'ABSPATH' ) || exit;

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter

/**
 * Class GGM_Commerce_Wishlist
 */
class GGM_Commerce_Wishlist {

	/**
	 * Table name for wishlists (master table).
	 *
	 * @var string
	 */
	private $wishlists_table;

	/**
	 * Table name for wishlist items.
	 *
	 * @var string
	 */
	private $items_table;

	/**
	 * Legacy table name (for backwards compatibility).
	 *
	 * @var string
	 */
	private $legacy_table;

	/**
	 * Cookie name for guest wishlist.
	 *
	 * @var string
	 */
	const COOKIE_NAME = 'ggmc_wishlist';

	/**
	 * Cookie expiration in days.
	 *
	 * @var int
	 */
	const COOKIE_EXPIRATION_DAYS = 30;

	/**
	 * Default maximum wishlists per user.
	 *
	 * @var int
	 */
	const DEFAULT_MAX_WISHLISTS = 5;

	/**
	 * Singleton instance.
	 *
	 * @var GGM_Commerce_Wishlist|null
	 */
	private static $instance = null;

	/**
	 * Get singleton instance.
	 *
	 * @return GGM_Commerce_Wishlist
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor.
	 */
	private function __construct() {
		global $wpdb;
		$this->wishlists_table = $wpdb->prefix . 'ggmc_wishlists';
		$this->items_table     = $wpdb->prefix . 'ggmc_wishlist_items';
		$this->legacy_table    = $wpdb->prefix . 'ggmc_wishlist';

		// Register AJAX actions for items.
		add_action( 'wp_ajax_ggmc_wishlist_add', array( $this, 'ajax_add_to_wishlist' ) );
		add_action( 'wp_ajax_nopriv_ggmc_wishlist_add', array( $this, 'ajax_add_to_wishlist' ) );

		add_action( 'wp_ajax_ggmc_wishlist_remove', array( $this, 'ajax_remove_from_wishlist' ) );
		add_action( 'wp_ajax_nopriv_ggmc_wishlist_remove', array( $this, 'ajax_remove_from_wishlist' ) );

		add_action( 'wp_ajax_ggmc_wishlist_toggle', array( $this, 'ajax_toggle_wishlist' ) );
		add_action( 'wp_ajax_nopriv_ggmc_wishlist_toggle', array( $this, 'ajax_toggle_wishlist' ) );

		add_action( 'wp_ajax_ggmc_wishlist_get', array( $this, 'ajax_get_wishlist' ) );
		add_action( 'wp_ajax_nopriv_ggmc_wishlist_get', array( $this, 'ajax_get_wishlist' ) );

		add_action( 'wp_ajax_ggmc_wishlist_clear', array( $this, 'ajax_clear_wishlist' ) );
		add_action( 'wp_ajax_nopriv_ggmc_wishlist_clear', array( $this, 'ajax_clear_wishlist' ) );

		// Register AJAX actions for wishlist management (logged-in users only).
		add_action( 'wp_ajax_ggmc_wishlist_create', array( $this, 'ajax_create_wishlist' ) );
		add_action( 'wp_ajax_ggmc_wishlist_update', array( $this, 'ajax_update_wishlist' ) );
		add_action( 'wp_ajax_ggmc_wishlist_delete', array( $this, 'ajax_delete_wishlist' ) );
		add_action( 'wp_ajax_ggmc_wishlist_set_default', array( $this, 'ajax_set_default_wishlist' ) );
		add_action( 'wp_ajax_ggmc_wishlist_get_all', array( $this, 'ajax_get_all_wishlists' ) );
		add_action( 'wp_ajax_ggmc_wishlist_move_items', array( $this, 'ajax_move_items' ) );
		add_action( 'wp_ajax_ggmc_wishlist_copy_items', array( $this, 'ajax_copy_items' ) );
		add_action( 'wp_ajax_ggmc_wishlist_share', array( $this, 'ajax_generate_share_link' ) );
		add_action( 'wp_ajax_ggmc_wishlist_get_items_html', array( $this, 'ajax_get_wishlist_items_html' ) );

		// Public endpoint for viewing shared wishlists.
		add_action( 'wp_ajax_nopriv_ggmc_wishlist_view_shared', array( $this, 'ajax_view_shared_wishlist' ) );
		add_action( 'wp_ajax_ggmc_wishlist_view_shared', array( $this, 'ajax_view_shared_wishlist' ) );

		// Merge guest wishlist when user logs in.
		add_action( 'wp_login', array( $this, 'merge_guest_wishlist_on_login' ), 10, 2 );

		// Run migration on init if needed.
		add_action( 'init', array( $this, 'maybe_run_migration' ) );

		// Output wishlist selector popover in footer.
		add_action( 'wp_footer', array( $this, 'output_wishlist_selector_popover' ) );
	}

	/**
	 * Run migration if needed.
	 */
	public function maybe_run_migration() {
		$db_version = get_option( 'ggmc_wishlist_db_version', '1.0' );
		if ( version_compare( $db_version, '2.0', '<' ) ) {
			GGM_Commerce_Database::migrate_wishlist_to_multi_list();
		}
	}

	/**
	 * Get admin-configured maximum wishlists.
	 *
	 * @return int Maximum number of wishlists per user.
	 */
	public function get_max_wishlists() {
		$widget_controls = get_option( 'ggm_commerce_widget_controls', array() );
		$max             = isset( $widget_controls['wishlist_max_lists'] ) ? absint( $widget_controls['wishlist_max_lists'] ) : self::DEFAULT_MAX_WISHLISTS;
		return max( 1, min( 20, $max ) );
	}

	/**
	 * Check if sharing is enabled.
	 *
	 * @return bool True if sharing is enabled.
	 */
	public function is_sharing_enabled() {
		$widget_controls = get_option( 'ggm_commerce_widget_controls', array() );
		return ! empty( $widget_controls['wishlist_sharing_enabled'] );
	}

	/**
	 * Check if current user is a guest.
	 *
	 * @return bool
	 */
	private function is_guest() {
		return ! is_user_logged_in();
	}

	// =========================================================================
	// WISHLIST MANAGEMENT METHODS (Create, Update, Delete, Get)
	// =========================================================================

	/**
	 * Create a new wishlist.
	 *
	 * @param string $name       Wishlist name.
	 * @param bool   $is_default Whether this is the default wishlist.
	 * @return array Result with success status, message, and wishlist data.
	 */
	public function create_wishlist( $name, $is_default = false ) {
		if ( $this->is_guest() ) {
			return array(
				'success' => false,
				'message' => __( 'Please log in to create wishlists.', 'ggm-commerce' ),
			);
		}

		global $wpdb;

		$user_id = get_current_user_id();
		$name    = sanitize_text_field( $name );

		if ( empty( $name ) ) {
			return array(
				'success' => false,
				'message' => __( 'Wishlist name is required.', 'ggm-commerce' ),
			);
		}

		// Check wishlist limit.
		$current_count = $this->get_wishlist_count_for_user( $user_id );
		$max_wishlists = $this->get_max_wishlists();

		if ( $current_count >= $max_wishlists ) {
			return array(
				'success' => false,
				'message' => sprintf(
					/* translators: %d: maximum number of wishlists */
					__( 'You can have a maximum of %d wishlists.', 'ggm-commerce' ),
					$max_wishlists
				),
			);
		}

		// Generate unique slug.
		$slug = GGM_Commerce_Database::generate_unique_wishlist_slug( $name, $user_id );

		// If setting as default, unset other defaults first.
		if ( $is_default ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->update(
				$this->wishlists_table,
				array( 'is_default' => 0 ),
				array( 'user_id' => $user_id ),
				array( '%d' ),
				array( '%d' )
			);
		}

		// Get next sort order.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$max_order = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT MAX(sort_order) FROM {$this->wishlists_table} WHERE user_id = %d",
				$user_id
			)
		);
		$sort_order = is_null( $max_order ) ? 0 : $max_order + 1;

		// Insert new wishlist.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
		$result = $wpdb->insert(
			$this->wishlists_table,
			array(
				'user_id'    => $user_id,
				'name'       => $name,
				'slug'       => $slug,
				'is_default' => $is_default ? 1 : 0,
				'is_public'  => 0,
				'sort_order' => $sort_order,
				'created_at' => current_time( 'mysql' ),
				'updated_at' => current_time( 'mysql' ),
			),
			array( '%d', '%s', '%s', '%d', '%d', '%d', '%s', '%s' )
		);

		if ( $result ) {
			$wishlist_id = $wpdb->insert_id;
			return array(
				'success'  => true,
				'message'  => __( 'Wishlist created successfully.', 'ggm-commerce' ),
				'wishlist' => array(
					'id'         => $wishlist_id,
					'name'       => $name,
					'slug'       => $slug,
					'is_default' => $is_default,
					'item_count' => 0,
				),
			);
		}

		return array(
			'success' => false,
			'message' => __( 'Failed to create wishlist.', 'ggm-commerce' ),
		);
	}

	/**
	 * Update a wishlist.
	 *
	 * @param int    $wishlist_id Wishlist ID.
	 * @param string $name        New name for the wishlist.
	 * @return array Result with success status and message.
	 */
	public function update_wishlist( $wishlist_id, $name ) {
		if ( $this->is_guest() ) {
			return array(
				'success' => false,
				'message' => __( 'Please log in to update wishlists.', 'ggm-commerce' ),
			);
		}

		global $wpdb;

		$user_id     = get_current_user_id();
		$wishlist_id = absint( $wishlist_id );
		$name        = sanitize_text_field( $name );

		if ( empty( $name ) ) {
			return array(
				'success' => false,
				'message' => __( 'Wishlist name is required.', 'ggm-commerce' ),
			);
		}

		// Verify ownership.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wishlist = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$this->wishlists_table} WHERE id = %d AND user_id = %d",
				$wishlist_id,
				$user_id
			)
		);

		if ( ! $wishlist ) {
			return array(
				'success' => false,
				'message' => __( 'Wishlist not found.', 'ggm-commerce' ),
			);
		}

		// Generate new slug if name changed.
		$slug = $wishlist->slug;
		if ( $name !== $wishlist->name ) {
			$slug = GGM_Commerce_Database::generate_unique_wishlist_slug( $name, $user_id, $wishlist_id );
		}

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$result = $wpdb->update(
			$this->wishlists_table,
			array(
				'name'       => $name,
				'slug'       => $slug,
				'updated_at' => current_time( 'mysql' ),
			),
			array( 'id' => $wishlist_id ),
			array( '%s', '%s', '%s' ),
			array( '%d' )
		);

		if ( false !== $result ) {
			return array(
				'success'  => true,
				'message'  => __( 'Wishlist updated successfully.', 'ggm-commerce' ),
				'wishlist' => array(
					'id'   => $wishlist_id,
					'name' => $name,
					'slug' => $slug,
				),
			);
		}

		return array(
			'success' => false,
			'message' => __( 'Failed to update wishlist.', 'ggm-commerce' ),
		);
	}

	/**
	 * Delete a wishlist.
	 *
	 * @param int  $wishlist_id       Wishlist ID.
	 * @param bool $move_items_to_default Move items to default wishlist instead of deleting.
	 * @return array Result with success status and message.
	 */
	public function delete_wishlist( $wishlist_id, $move_items_to_default = false ) {
		if ( $this->is_guest() ) {
			return array(
				'success' => false,
				'message' => __( 'Please log in to delete wishlists.', 'ggm-commerce' ),
			);
		}

		global $wpdb;

		$user_id     = get_current_user_id();
		$wishlist_id = absint( $wishlist_id );

		// Verify ownership.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wishlist = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$this->wishlists_table} WHERE id = %d AND user_id = %d",
				$wishlist_id,
				$user_id
			)
		);

		if ( ! $wishlist ) {
			return array(
				'success' => false,
				'message' => __( 'Wishlist not found.', 'ggm-commerce' ),
			);
		}

		// Cannot delete default wishlist if it's the only one.
		if ( $wishlist->is_default ) {
			$count = $this->get_wishlist_count_for_user( $user_id );
			if ( $count <= 1 ) {
				return array(
					'success' => false,
					'message' => __( 'Cannot delete your only wishlist.', 'ggm-commerce' ),
				);
			}
		}

		// Handle items.
		if ( $move_items_to_default && ! $wishlist->is_default ) {
			$default_wishlist = $this->get_default_wishlist();
			if ( $default_wishlist && $default_wishlist->id !== $wishlist_id ) {
				// Get items from the wishlist being deleted.
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$items = $wpdb->get_results(
					$wpdb->prepare(
						"SELECT product_id, date_added FROM {$this->items_table} WHERE wishlist_id = %d",
						$wishlist_id
					)
				);

				foreach ( $items as $item ) {
					// Check if product already in default wishlist.
					// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
					$exists = $wpdb->get_var(
						$wpdb->prepare(
							"SELECT id FROM {$this->items_table} WHERE wishlist_id = %d AND product_id = %d",
							$default_wishlist->id,
							$item->product_id
						)
					);

					if ( ! $exists ) {
						// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
						$wpdb->insert(
							$this->items_table,
							array(
								'wishlist_id' => $default_wishlist->id,
								'product_id'  => $item->product_id,
								'date_added'  => $item->date_added,
							),
							array( '%d', '%d', '%s' )
						);
					}
				}
			}
		}

		// Delete items.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->delete(
			$this->items_table,
			array( 'wishlist_id' => $wishlist_id ),
			array( '%d' )
		);

		// Delete wishlist.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$result = $wpdb->delete(
			$this->wishlists_table,
			array( 'id' => $wishlist_id ),
			array( '%d' )
		);

		// If deleted wishlist was default, set a new default.
		if ( $result && $wishlist->is_default ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$new_default = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT id FROM {$this->wishlists_table} WHERE user_id = %d ORDER BY sort_order ASC LIMIT 1",
					$user_id
				)
			);

			if ( $new_default ) {
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$wpdb->update(
					$this->wishlists_table,
					array( 'is_default' => 1 ),
					array( 'id' => $new_default ),
					array( '%d' ),
					array( '%d' )
				);
			}
		}

		if ( $result ) {
			return array(
				'success' => true,
				'message' => __( 'Wishlist deleted successfully.', 'ggm-commerce' ),
			);
		}

		return array(
			'success' => false,
			'message' => __( 'Failed to delete wishlist.', 'ggm-commerce' ),
		);
	}

	/**
	 * Get all wishlists for current user.
	 *
	 * @param bool $include_item_counts Include item counts for each wishlist.
	 * @return array Array of wishlist objects.
	 */
	public function get_wishlists( $include_item_counts = true ) {
		if ( $this->is_guest() ) {
			// Return a "virtual" default wishlist for guests.
			$guest_items = $this->get_guest_wishlist();
			return array(
				(object) array(
					'id'         => 0,
					'name'       => __( 'My Wishlist', 'ggm-commerce' ),
					'slug'       => 'my-wishlist',
					'is_default' => 1,
					'is_public'  => 0,
					'item_count' => count( $guest_items ),
				),
			);
		}

		global $wpdb;

		$user_id = get_current_user_id();

		if ( $include_item_counts ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wishlists = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT w.*, COUNT(i.id) as item_count
					FROM {$this->wishlists_table} w
					LEFT JOIN {$this->items_table} i ON w.id = i.wishlist_id
					WHERE w.user_id = %d
					GROUP BY w.id
					ORDER BY w.sort_order ASC, w.created_at ASC",
					$user_id
				)
			);
		} else {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wishlists = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT * FROM {$this->wishlists_table} WHERE user_id = %d ORDER BY sort_order ASC, created_at ASC",
					$user_id
				)
			);
		}

		// If no wishlists, create a default one.
		if ( empty( $wishlists ) ) {
			$result = $this->create_wishlist( __( 'My Wishlist', 'ggm-commerce' ), true );
			if ( $result['success'] ) {
				return $this->get_wishlists( $include_item_counts );
			}
		}

		// Ensure only one wishlist is marked as default.
		// If multiple defaults exist (e.g. from failed operations), fix by
		// keeping only the first one as default.
		$default_count = 0;
		foreach ( $wishlists as $wl ) {
			if ( ! empty( $wl->is_default ) ) {
				$default_count++;
				if ( $default_count > 1 ) {
					$wl->is_default = 0;
					// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
					$wpdb->update(
						$this->wishlists_table,
						array( 'is_default' => 0 ),
						array( 'id' => $wl->id ),
						array( '%d' ),
						array( '%d' )
					);
				}
			}
		}

		return $wishlists;
	}

	/**
	 * Get a single wishlist.
	 *
	 * @param int $wishlist_id Wishlist ID.
	 * @return object|null Wishlist object or null.
	 */
	public function get_wishlist( $wishlist_id ) {
		if ( $this->is_guest() && 0 === absint( $wishlist_id ) ) {
			// Return virtual guest wishlist.
			$guest_items = $this->get_guest_wishlist();
			return (object) array(
				'id'         => 0,
				'name'       => __( 'My Wishlist', 'ggm-commerce' ),
				'slug'       => 'my-wishlist',
				'is_default' => 1,
				'is_public'  => 0,
				'item_count' => count( $guest_items ),
			);
		}

		global $wpdb;

		$user_id     = get_current_user_id();
		$wishlist_id = absint( $wishlist_id );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		return $wpdb->get_row(
			$wpdb->prepare(
				"SELECT w.*, COUNT(i.id) as item_count
				FROM {$this->wishlists_table} w
				LEFT JOIN {$this->items_table} i ON w.id = i.wishlist_id
				WHERE w.id = %d AND w.user_id = %d
				GROUP BY w.id",
				$wishlist_id,
				$user_id
			)
		);
	}

	/**
	 * Get or create the default wishlist for current user.
	 *
	 * @return object|null Wishlist object or null.
	 */
	public function get_default_wishlist() {
		if ( $this->is_guest() ) {
			return $this->get_wishlist( 0 );
		}

		global $wpdb;

		$user_id = get_current_user_id();

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$default = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$this->wishlists_table} WHERE user_id = %d AND is_default = 1",
				$user_id
			)
		);

		if ( ! $default ) {
			// Create default wishlist.
			$result = $this->create_wishlist( __( 'My Wishlist', 'ggm-commerce' ), true );
			if ( $result['success'] ) {
				return $this->get_default_wishlist();
			}
		}

		return $default;
	}

	/**
	 * Set a wishlist as the default.
	 *
	 * @param int $wishlist_id Wishlist ID.
	 * @return array Result with success status and message.
	 */
	public function set_default_wishlist( $wishlist_id ) {
		if ( $this->is_guest() ) {
			return array(
				'success' => false,
				'message' => __( 'Please log in to manage wishlists.', 'ggm-commerce' ),
			);
		}

		global $wpdb;

		$user_id     = get_current_user_id();
		$wishlist_id = absint( $wishlist_id );

		// Verify ownership.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wishlist = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT id FROM {$this->wishlists_table} WHERE id = %d AND user_id = %d",
				$wishlist_id,
				$user_id
			)
		);

		if ( ! $wishlist ) {
			return array(
				'success' => false,
				'message' => __( 'Wishlist not found.', 'ggm-commerce' ),
			);
		}

		// Unset all defaults for this user.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->update(
			$this->wishlists_table,
			array( 'is_default' => 0 ),
			array( 'user_id' => $user_id ),
			array( '%d' ),
			array( '%d' )
		);

		// Set new default.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$result = $wpdb->update(
			$this->wishlists_table,
			array( 'is_default' => 1 ),
			array( 'id' => $wishlist_id ),
			array( '%d' ),
			array( '%d' )
		);

		if ( false !== $result ) {
			return array(
				'success' => true,
				'message' => __( 'Default wishlist updated.', 'ggm-commerce' ),
			);
		}

		return array(
			'success' => false,
			'message' => __( 'Failed to set default wishlist.', 'ggm-commerce' ),
		);
	}

	/**
	 * Get wishlist count for a user.
	 *
	 * @param int $user_id User ID.
	 * @return int Number of wishlists.
	 */
	private function get_wishlist_count_for_user( $user_id ) {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		return (int) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$this->wishlists_table} WHERE user_id = %d",
				$user_id
			)
		);
	}

	// =========================================================================
	// ITEM MANAGEMENT METHODS
	// =========================================================================

	/**
	 * Get guest wishlist from cookie.
	 *
	 * @return array Product IDs in guest wishlist.
	 */
	private function get_guest_wishlist() {
		if ( isset( $_COOKIE[ self::COOKIE_NAME ] ) ) {
			$wishlist = json_decode( sanitize_text_field( wp_unslash( $_COOKIE[ self::COOKIE_NAME ] ) ), true );
			if ( is_array( $wishlist ) ) {
				return array_map( 'intval', $wishlist );
			}
		}
		return array();
	}

	/**
	 * Save guest wishlist to cookie.
	 *
	 * @param array $product_ids Product IDs to save.
	 */
	private function save_guest_wishlist( $product_ids ) {
		$expiration = time() + ( self::COOKIE_EXPIRATION_DAYS * DAY_IN_SECONDS );
		$value      = wp_json_encode( array_values( array_unique( array_map( 'intval', $product_ids ) ) ) );

		// Set cookie with secure flags.
		setcookie(
			self::COOKIE_NAME,
			$value,
			array(
				'expires'  => $expiration,
				'path'     => COOKIEPATH,
				'domain'   => COOKIE_DOMAIN,
				'secure'   => is_ssl(),
				'httponly' => false, // Allow JS access for immediate UI updates.
				'samesite' => 'Lax',
			)
		);

		// Also update $_COOKIE for immediate access in same request.
		$_COOKIE[ self::COOKIE_NAME ] = $value;
	}

	/**
	 * Add a product to the wishlist.
	 *
	 * @param int      $product_id  Product ID to add.
	 * @param int|null $wishlist_id Wishlist ID (null = default wishlist).
	 * @return array Result with success status and message.
	 */
	public function add_item( $product_id, $wishlist_id = null ) {
		$product_id = absint( $product_id );

		if ( ! $product_id ) {
			return array(
				'success' => false,
				'message' => __( 'Invalid product ID.', 'ggm-commerce' ),
			);
		}

		// Verify product exists.
		if ( ! $this->product_exists( $product_id ) ) {
			return array(
				'success' => false,
				'message' => __( 'Product not found.', 'ggm-commerce' ),
			);
		}

		if ( $this->is_guest() ) {
			// Handle guest wishlist via cookie.
			$wishlist = $this->get_guest_wishlist();

			if ( in_array( $product_id, $wishlist, true ) ) {
				return array(
					'success' => true,
					'message' => __( 'Product already in wishlist.', 'ggm-commerce' ),
					'action'  => 'exists',
					'count'   => count( $wishlist ),
				);
			}

			$wishlist[] = $product_id;
			$this->save_guest_wishlist( $wishlist );

			return array(
				'success' => true,
				'message' => __( 'Product added to wishlist.', 'ggm-commerce' ),
				'action'  => 'added',
				'count'   => count( $wishlist ),
			);
		}

		// Handle logged-in user wishlist via database.
		global $wpdb;

		// Get target wishlist.
		if ( null === $wishlist_id ) {
			$wishlist = $this->get_default_wishlist();
			if ( ! $wishlist ) {
				return array(
					'success' => false,
					'message' => __( 'Could not find or create default wishlist.', 'ggm-commerce' ),
				);
			}
			$wishlist_id = $wishlist->id;
		} else {
			$wishlist = $this->get_wishlist( $wishlist_id );
			if ( ! $wishlist ) {
				return array(
					'success' => false,
					'message' => __( 'Wishlist not found.', 'ggm-commerce' ),
				);
			}
		}

		// Check if already in wishlist.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$exists = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT id FROM {$this->items_table} WHERE wishlist_id = %d AND product_id = %d",
				$wishlist_id,
				$product_id
			)
		);

		if ( $exists ) {
			return array(
				'success'     => true,
				'message'     => __( 'Product already in wishlist.', 'ggm-commerce' ),
				'action'      => 'exists',
				'count'       => $this->get_count(),
				'wishlist_id' => $wishlist_id,
			);
		}

		// Insert new wishlist item.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
		$result = $wpdb->insert(
			$this->items_table,
			array(
				'wishlist_id' => $wishlist_id,
				'product_id'  => $product_id,
				'date_added'  => current_time( 'mysql' ),
			),
			array( '%d', '%d', '%s' )
		);

		if ( $result ) {
			return array(
				'success'     => true,
				'message'     => __( 'Product added to wishlist.', 'ggm-commerce' ),
				'action'      => 'added',
				'count'       => $this->get_count(),
				'wishlist_id' => $wishlist_id,
			);
		}

		return array(
			'success' => false,
			'message' => __( 'Failed to add product to wishlist.', 'ggm-commerce' ),
		);
	}

	/**
	 * Remove a product from the wishlist.
	 *
	 * @param int      $product_id  Product ID to remove.
	 * @param int|null $wishlist_id Wishlist ID (null = remove from all wishlists).
	 * @return array Result with success status and message.
	 */
	public function remove_item( $product_id, $wishlist_id = null ) {
		$product_id = absint( $product_id );

		if ( ! $product_id ) {
			return array(
				'success' => false,
				'message' => __( 'Invalid product ID.', 'ggm-commerce' ),
			);
		}

		if ( $this->is_guest() ) {
			// Handle guest wishlist via cookie.
			$wishlist = $this->get_guest_wishlist();
			$key      = array_search( $product_id, $wishlist, true );

			if ( false === $key ) {
				return array(
					'success' => true,
					'message' => __( 'Product not in wishlist.', 'ggm-commerce' ),
					'action'  => 'not_found',
					'count'   => count( $wishlist ),
				);
			}

			unset( $wishlist[ $key ] );
			$this->save_guest_wishlist( $wishlist );

			return array(
				'success' => true,
				'message' => __( 'Product removed from wishlist.', 'ggm-commerce' ),
				'action'  => 'removed',
				'count'   => count( $wishlist ),
			);
		}

		// Handle logged-in user wishlist via database.
		global $wpdb;

		$user_id = get_current_user_id();

		if ( null === $wishlist_id ) {
			// Remove from all user's wishlists.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$deleted = $wpdb->query(
				$wpdb->prepare(
					"DELETE i FROM {$this->items_table} i
					INNER JOIN {$this->wishlists_table} w ON i.wishlist_id = w.id
					WHERE w.user_id = %d AND i.product_id = %d",
					$user_id,
					$product_id
				)
			);
		} else {
			// Verify ownership of wishlist.
			$wishlist = $this->get_wishlist( $wishlist_id );
			if ( ! $wishlist ) {
				return array(
					'success' => false,
					'message' => __( 'Wishlist not found.', 'ggm-commerce' ),
				);
			}

			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$deleted = $wpdb->delete(
				$this->items_table,
				array(
					'wishlist_id' => $wishlist_id,
					'product_id'  => $product_id,
				),
				array( '%d', '%d' )
			);
		}

		if ( $deleted ) {
			return array(
				'success'     => true,
				'message'     => __( 'Product removed from wishlist.', 'ggm-commerce' ),
				'action'      => 'removed',
				'count'       => $this->get_count(),
				'wishlist_id' => $wishlist_id,
			);
		}

		return array(
			'success' => true,
			'message' => __( 'Product not in wishlist.', 'ggm-commerce' ),
			'action'  => 'not_found',
			'count'   => $this->get_count(),
		);
	}

	/**
	 * Toggle a product in the wishlist (add if not present, remove if present).
	 *
	 * @param int      $product_id  Product ID to toggle.
	 * @param int|null $wishlist_id Wishlist ID (null = default wishlist).
	 * @return array Result with success status and action taken.
	 */
	public function toggle_item( $product_id, $wishlist_id = null ) {
		$product_id = absint( $product_id );

		if ( $this->is_in_wishlist( $product_id, $wishlist_id ) ) {
			return $this->remove_item( $product_id, $wishlist_id );
		}

		return $this->add_item( $product_id, $wishlist_id );
	}

	/**
	 * Check if a product is in the wishlist.
	 *
	 * @param int      $product_id  Product ID to check.
	 * @param int|null $wishlist_id Wishlist ID (null = check any wishlist).
	 * @return bool True if product is in wishlist.
	 */
	public function is_in_wishlist( $product_id, $wishlist_id = null ) {
		$product_id = absint( $product_id );

		if ( ! $product_id ) {
			return false;
		}

		if ( $this->is_guest() ) {
			$wishlist = $this->get_guest_wishlist();
			return in_array( $product_id, $wishlist, true );
		}

		global $wpdb;

		$user_id = get_current_user_id();

		if ( null === $wishlist_id ) {
			// Check any of user's wishlists.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$exists = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT i.id FROM {$this->items_table} i
					INNER JOIN {$this->wishlists_table} w ON i.wishlist_id = w.id
					WHERE w.user_id = %d AND i.product_id = %d
					LIMIT 1",
					$user_id,
					$product_id
				)
			);
		} else {
			// Check specific wishlist.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$exists = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT i.id FROM {$this->items_table} i
					INNER JOIN {$this->wishlists_table} w ON i.wishlist_id = w.id
					WHERE w.user_id = %d AND w.id = %d AND i.product_id = %d",
					$user_id,
					$wishlist_id,
					$product_id
				)
			);
		}

		return (bool) $exists;
	}

	/**
	 * Get all product IDs in the wishlist.
	 *
	 * @param int|null $wishlist_id Wishlist ID (null = all wishlists).
	 * @return array Product IDs.
	 */
	public function get_product_ids( $wishlist_id = null ) {
		if ( $this->is_guest() ) {
			return $this->get_guest_wishlist();
		}

		global $wpdb;

		$user_id = get_current_user_id();

		if ( null === $wishlist_id ) {
			// Get from all user's wishlists.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$results = $wpdb->get_col(
				$wpdb->prepare(
					"SELECT DISTINCT i.product_id FROM {$this->items_table} i
					INNER JOIN {$this->wishlists_table} w ON i.wishlist_id = w.id
					WHERE w.user_id = %d
					ORDER BY i.date_added DESC",
					$user_id
				)
			);
		} else {
			// Get from specific wishlist.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$results = $wpdb->get_col(
				$wpdb->prepare(
					"SELECT i.product_id FROM {$this->items_table} i
					INNER JOIN {$this->wishlists_table} w ON i.wishlist_id = w.id
					WHERE w.user_id = %d AND w.id = %d
					ORDER BY i.date_added DESC",
					$user_id,
					$wishlist_id
				)
			);
		}

		return array_map( 'intval', $results );
	}

	/**
	 * Get all wishlist items with product data.
	 *
	 * @param int|null $wishlist_id Wishlist ID (null = all wishlists).
	 * @return array Wishlist items with product details.
	 */
	public function get_items( $wishlist_id = null ) {
		$product_ids = $this->get_product_ids( $wishlist_id );

		if ( empty( $product_ids ) ) {
			return array();
		}

		global $wpdb;

		$products_table = $wpdb->prefix . 'ggmc_products';
		$placeholders   = implode( ', ', array_fill( 0, count( $product_ids ), '%d' ) );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
		$products = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT id, name, slug, sku, short_description, price, sale_price, stock, stock_status, image_id
				FROM {$products_table}
				WHERE id IN ({$placeholders})
				AND (status = 'active' OR status IS NULL)",
				...$product_ids
			)
		);

		// Add image URLs to products.
		foreach ( $products as $product ) {
			$product->image_url = '';
			if ( $product->image_id ) {
				$image_url = wp_get_attachment_image_url( $product->image_id, 'medium' );
				if ( $image_url ) {
					$product->image_url = $image_url;
				}
			}

			// Calculate effective price.
			$product->effective_price = $product->sale_price && $product->sale_price > 0
				? $product->sale_price
				: $product->price;
		}

		return $products;
	}

	/**
	 * Get wishlist count.
	 *
	 * @param int|null $wishlist_id Wishlist ID (null = total across all wishlists).
	 * @return int Number of items in wishlist.
	 */
	public function get_count( $wishlist_id = null ) {
		if ( $this->is_guest() ) {
			return count( $this->get_guest_wishlist() );
		}

		global $wpdb;

		$user_id = get_current_user_id();

		if ( null === $wishlist_id ) {
			// Total count across all wishlists.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$count = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(DISTINCT i.product_id) FROM {$this->items_table} i
					INNER JOIN {$this->wishlists_table} w ON i.wishlist_id = w.id
					WHERE w.user_id = %d",
					$user_id
				)
			);
		} else {
			// Count for specific wishlist.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$count = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$this->items_table} i
					INNER JOIN {$this->wishlists_table} w ON i.wishlist_id = w.id
					WHERE w.user_id = %d AND w.id = %d",
					$user_id,
					$wishlist_id
				)
			);
		}

		return (int) $count;
	}

	/**
	 * Clear all items from the wishlist.
	 *
	 * @param int|null $wishlist_id Wishlist ID (null = clear all wishlists).
	 * @return array Result with success status.
	 */
	public function clear( $wishlist_id = null ) {
		if ( $this->is_guest() ) {
			$this->save_guest_wishlist( array() );
			return array(
				'success' => true,
				'message' => __( 'Wishlist cleared.', 'ggm-commerce' ),
				'count'   => 0,
			);
		}

		global $wpdb;

		$user_id = get_current_user_id();

		if ( null === $wishlist_id ) {
			// Clear all user's wishlists.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->query(
				$wpdb->prepare(
					"DELETE i FROM {$this->items_table} i
					INNER JOIN {$this->wishlists_table} w ON i.wishlist_id = w.id
					WHERE w.user_id = %d",
					$user_id
				)
			);
		} else {
			// Clear specific wishlist.
			$wishlist = $this->get_wishlist( $wishlist_id );
			if ( ! $wishlist ) {
				return array(
					'success' => false,
					'message' => __( 'Wishlist not found.', 'ggm-commerce' ),
				);
			}

			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->delete(
				$this->items_table,
				array( 'wishlist_id' => $wishlist_id ),
				array( '%d' )
			);
		}

		return array(
			'success'     => true,
			'message'     => __( 'Wishlist cleared.', 'ggm-commerce' ),
			'count'       => 0,
			'wishlist_id' => $wishlist_id,
		);
	}

	// =========================================================================
	// MOVE/COPY ITEMS BETWEEN WISHLISTS
	// =========================================================================

	/**
	 * Move items between wishlists.
	 *
	 * @param array $product_ids    Product IDs to move.
	 * @param int   $from_wishlist  Source wishlist ID.
	 * @param int   $to_wishlist    Destination wishlist ID.
	 * @return array Result with success status and message.
	 */
	public function move_items( $product_ids, $from_wishlist, $to_wishlist ) {
		if ( $this->is_guest() ) {
			return array(
				'success' => false,
				'message' => __( 'Please log in to move items between wishlists.', 'ggm-commerce' ),
			);
		}

		$product_ids   = array_map( 'absint', (array) $product_ids );
		$from_wishlist = absint( $from_wishlist );
		$to_wishlist   = absint( $to_wishlist );

		// Verify both wishlists exist and belong to user.
		$from = $this->get_wishlist( $from_wishlist );
		$to   = $this->get_wishlist( $to_wishlist );

		if ( ! $from || ! $to ) {
			return array(
				'success' => false,
				'message' => __( 'Wishlist not found.', 'ggm-commerce' ),
			);
		}

		global $wpdb;

		$moved = 0;
		foreach ( $product_ids as $product_id ) {
			// Check if item exists in source.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$item = $wpdb->get_row(
				$wpdb->prepare(
					"SELECT * FROM {$this->items_table} WHERE wishlist_id = %d AND product_id = %d",
					$from_wishlist,
					$product_id
				)
			);

			if ( ! $item ) {
				continue;
			}

			// Check if already in destination.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$exists = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT id FROM {$this->items_table} WHERE wishlist_id = %d AND product_id = %d",
					$to_wishlist,
					$product_id
				)
			);

			if ( $exists ) {
				// Just delete from source.
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$wpdb->delete(
					$this->items_table,
					array( 'id' => $item->id ),
					array( '%d' )
				);
			} else {
				// Update wishlist_id.
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$wpdb->update(
					$this->items_table,
					array( 'wishlist_id' => $to_wishlist ),
					array( 'id' => $item->id ),
					array( '%d' ),
					array( '%d' )
				);
			}
			$moved++;
		}

		return array(
			'success' => true,
			'message' => sprintf(
				/* translators: %d: number of items moved */
				__( '%d items moved successfully.', 'ggm-commerce' ),
				$moved
			),
			'moved'   => $moved,
		);
	}

	/**
	 * Copy items between wishlists.
	 *
	 * @param array $product_ids    Product IDs to copy.
	 * @param int   $from_wishlist  Source wishlist ID.
	 * @param int   $to_wishlist    Destination wishlist ID.
	 * @return array Result with success status and message.
	 */
	public function copy_items( $product_ids, $from_wishlist, $to_wishlist ) {
		if ( $this->is_guest() ) {
			return array(
				'success' => false,
				'message' => __( 'Please log in to copy items between wishlists.', 'ggm-commerce' ),
			);
		}

		$product_ids   = array_map( 'absint', (array) $product_ids );
		$from_wishlist = absint( $from_wishlist );
		$to_wishlist   = absint( $to_wishlist );

		// Verify both wishlists exist and belong to user.
		$from = $this->get_wishlist( $from_wishlist );
		$to   = $this->get_wishlist( $to_wishlist );

		if ( ! $from || ! $to ) {
			return array(
				'success' => false,
				'message' => __( 'Wishlist not found.', 'ggm-commerce' ),
			);
		}

		global $wpdb;

		$copied = 0;
		foreach ( $product_ids as $product_id ) {
			// Check if already in destination.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$exists = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT id FROM {$this->items_table} WHERE wishlist_id = %d AND product_id = %d",
					$to_wishlist,
					$product_id
				)
			);

			if ( $exists ) {
				continue;
			}

			// Insert into destination.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
			$result = $wpdb->insert(
				$this->items_table,
				array(
					'wishlist_id' => $to_wishlist,
					'product_id'  => $product_id,
					'date_added'  => current_time( 'mysql' ),
				),
				array( '%d', '%d', '%s' )
			);

			if ( $result ) {
				$copied++;
			}
		}

		return array(
			'success' => true,
			'message' => sprintf(
				/* translators: %d: number of items copied */
				__( '%d items copied successfully.', 'ggm-commerce' ),
				$copied
			),
			'copied'  => $copied,
		);
	}

	// =========================================================================
	// SHARING FUNCTIONALITY
	// =========================================================================

	/**
	 * Generate a share token for a wishlist.
	 *
	 * @param int $wishlist_id Wishlist ID.
	 * @return array Result with success status and share URL.
	 */
	public function generate_share_token( $wishlist_id ) {
		if ( ! $this->is_sharing_enabled() ) {
			return array(
				'success' => false,
				'message' => __( 'Wishlist sharing is disabled.', 'ggm-commerce' ),
			);
		}

		if ( $this->is_guest() ) {
			return array(
				'success' => false,
				'message' => __( 'Please log in to share wishlists.', 'ggm-commerce' ),
			);
		}

		global $wpdb;

		$wishlist = $this->get_wishlist( $wishlist_id );
		if ( ! $wishlist ) {
			return array(
				'success' => false,
				'message' => __( 'Wishlist not found.', 'ggm-commerce' ),
			);
		}

		// Generate unique token.
		$token = wp_generate_password( 32, false );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$result = $wpdb->update(
			$this->wishlists_table,
			array(
				'share_token' => $token,
				'is_public'   => 1,
				'updated_at'  => current_time( 'mysql' ),
			),
			array( 'id' => $wishlist_id ),
			array( '%s', '%d', '%s' ),
			array( '%d' )
		);

		if ( false !== $result ) {
			$share_url = add_query_arg(
				array(
					'wishlist' => $token,
				),
				home_url( '/wishlist/' )
			);

			return array(
				'success'   => true,
				'message'   => __( 'Share link generated.', 'ggm-commerce' ),
				'token'     => $token,
				'share_url' => $share_url,
			);
		}

		return array(
			'success' => false,
			'message' => __( 'Failed to generate share link.', 'ggm-commerce' ),
		);
	}

	/**
	 * Get a wishlist by share token.
	 *
	 * @param string $token Share token.
	 * @return array|null Wishlist data or null if not found.
	 */
	public function get_shared_wishlist( $token ) {
		if ( ! $this->is_sharing_enabled() ) {
			return null;
		}

		global $wpdb;

		$token = sanitize_text_field( $token );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wishlist = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT w.*, u.display_name as owner_name
				FROM {$this->wishlists_table} w
				LEFT JOIN {$wpdb->users} u ON w.user_id = u.ID
				WHERE w.share_token = %s AND w.is_public = 1",
				$token
			)
		);

		if ( ! $wishlist ) {
			return null;
		}

		// Get items.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$product_ids = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT product_id FROM {$this->items_table} WHERE wishlist_id = %d ORDER BY date_added DESC",
				$wishlist->id
			)
		);

		$products = array();
		if ( ! empty( $product_ids ) ) {
			$products_table = $wpdb->prefix . 'ggmc_products';
			$placeholders   = implode( ', ', array_fill( 0, count( $product_ids ), '%d' ) );

			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
			$products = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT id, name, slug, sku, price, sale_price, stock_status, image_id
					FROM {$products_table}
					WHERE id IN ({$placeholders})
					AND (status = 'active' OR status IS NULL)",
					...$product_ids
				)
			);

			// Add image URLs.
			foreach ( $products as $product ) {
				$product->image_url = '';
				if ( $product->image_id ) {
					$image_url = wp_get_attachment_image_url( $product->image_id, 'medium' );
					if ( $image_url ) {
						$product->image_url = $image_url;
					}
				}
				$product->effective_price = $product->sale_price && $product->sale_price > 0
					? $product->sale_price
					: $product->price;
			}
		}

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

	// =========================================================================
	// MERGE GUEST WISHLIST ON LOGIN
	// =========================================================================

	/**
	 * Merge guest wishlist into user wishlist on login.
	 *
	 * @param string  $user_login Username.
	 * @param WP_User $user       User object.
	 */
	public function merge_guest_wishlist_on_login( $user_login, $user ) {
		$guest_wishlist = $this->get_guest_wishlist();

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

		global $wpdb;

		// Get or create default wishlist for user.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$default_wishlist = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT id FROM {$this->wishlists_table} WHERE user_id = %d AND is_default = 1",
				$user->ID
			)
		);

		if ( ! $default_wishlist ) {
			// Create default wishlist.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
			$wpdb->insert(
				$this->wishlists_table,
				array(
					'user_id'    => $user->ID,
					'name'       => __( 'My Wishlist', 'ggm-commerce' ),
					'slug'       => 'my-wishlist',
					'is_default' => 1,
					'is_public'  => 0,
					'sort_order' => 0,
					'created_at' => current_time( 'mysql' ),
					'updated_at' => current_time( 'mysql' ),
				),
				array( '%d', '%s', '%s', '%d', '%d', '%d', '%s', '%s' )
			);
			$wishlist_id = $wpdb->insert_id;
		} else {
			$wishlist_id = $default_wishlist->id;
		}

		foreach ( $guest_wishlist as $product_id ) {
			// Check if already exists.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$exists = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT id FROM {$this->items_table} WHERE wishlist_id = %d AND product_id = %d",
					$wishlist_id,
					$product_id
				)
			);

			if ( ! $exists ) {
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
				$wpdb->insert(
					$this->items_table,
					array(
						'wishlist_id' => $wishlist_id,
						'product_id'  => $product_id,
						'date_added'  => current_time( 'mysql' ),
					),
					array( '%d', '%d', '%s' )
				);
			}
		}

		// Clear guest cookie after merge.
		$this->save_guest_wishlist( array() );
	}

	// =========================================================================
	// HELPER METHODS
	// =========================================================================

	/**
	 * Check if a product exists in the database.
	 *
	 * @param int $product_id Product ID.
	 * @return bool
	 */
	private function product_exists( $product_id ) {
		global $wpdb;

		$products_table = $wpdb->prefix . 'ggmc_products';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$exists = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT id FROM {$products_table} WHERE id = %d",
				$product_id
			)
		);

		return (bool) $exists;
	}

	/**
	 * Verify AJAX nonce.
	 *
	 * @return bool True if nonce is valid.
	 */
	private function verify_ajax_nonce() {
		$nonce = '';
		if ( isset( $_POST['nonce'] ) ) {
			$nonce = sanitize_text_field( wp_unslash( $_POST['nonce'] ) );
		} elseif ( isset( $_GET['nonce'] ) ) {
			$nonce = sanitize_text_field( wp_unslash( $_GET['nonce'] ) );
		}

		return wp_verify_nonce( $nonce, 'ggm_commerce_nonce' );
	}

	/**
	 * Clean any output buffered before an AJAX response.
	 *
	 * When WP_DEBUG_DISPLAY is true, PHP warnings/notices from plugins or
	 * WordPress itself may be echoed before the JSON response, corrupting it
	 * and causing jQuery to trigger its error callback.
	 */
	private function clean_ajax_output_buffer() {
		if ( ob_get_level() > 0 && ob_get_length() > 0 ) {
			ob_clean();
		}
	}

	// =========================================================================
	// AJAX HANDLERS - ITEM OPERATIONS
	// =========================================================================

	/**
	 * AJAX: Add product to wishlist.
	 */
	public function ajax_add_to_wishlist() {
		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$product_id  = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
		$wishlist_id = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : null;

		if ( 0 === $wishlist_id ) {
			$wishlist_id = null;
		}

		$result = $this->add_item( $product_id, $wishlist_id );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: Remove product from wishlist.
	 */
	public function ajax_remove_from_wishlist() {
		$this->clean_ajax_output_buffer();

		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$product_id  = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
		$wishlist_id = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : null;

		if ( 0 === $wishlist_id ) {
			$wishlist_id = null;
		}

		$result = $this->remove_item( $product_id, $wishlist_id );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: Toggle product in wishlist.
	 */
	public function ajax_toggle_wishlist() {
		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$product_id  = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
		$wishlist_id = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : null;

		if ( 0 === $wishlist_id ) {
			$wishlist_id = null;
		}

		$result = $this->toggle_item( $product_id, $wishlist_id );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: Get wishlist data.
	 */
	public function ajax_get_wishlist() {
		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$include_products = isset( $_POST['include_products'] ) && $_POST['include_products'];
		$wishlist_id      = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : null;

		if ( 0 === $wishlist_id ) {
			$wishlist_id = null;
		}

		$response = array(
			'success'     => true,
			'count'       => $this->get_count( $wishlist_id ),
			'product_ids' => $this->get_product_ids( $wishlist_id ),
		);

		if ( $include_products ) {
			$response['products'] = $this->get_items( $wishlist_id );
		}

		wp_send_json_success( $response );
	}

	/**
	 * AJAX: Clear wishlist.
	 */
	public function ajax_clear_wishlist() {
		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$wishlist_id = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : null;

		if ( 0 === $wishlist_id ) {
			$wishlist_id = null;
		}

		$result = $this->clear( $wishlist_id );
		wp_send_json_success( $result );
	}

	// =========================================================================
	// AJAX HANDLERS - WISHLIST MANAGEMENT
	// =========================================================================

	/**
	 * AJAX: Create a new wishlist.
	 */
	public function ajax_create_wishlist() {
		$this->clean_ajax_output_buffer();

		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$name       = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
		$is_default = isset( $_POST['is_default'] ) && $_POST['is_default'];

		$result = $this->create_wishlist( $name, $is_default );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: Update a wishlist.
	 */
	public function ajax_update_wishlist() {
		$this->clean_ajax_output_buffer();

		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$wishlist_id = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : 0;
		$name        = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';

		$result = $this->update_wishlist( $wishlist_id, $name );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: Delete a wishlist.
	 */
	public function ajax_delete_wishlist() {
		$this->clean_ajax_output_buffer();

		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$wishlist_id = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : 0;
		$move_items  = isset( $_POST['move_items'] ) && $_POST['move_items'];

		$result = $this->delete_wishlist( $wishlist_id, $move_items );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: Set default wishlist.
	 */
	public function ajax_set_default_wishlist() {
		$this->clean_ajax_output_buffer();

		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$wishlist_id = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : 0;

		$result = $this->set_default_wishlist( $wishlist_id );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: Get all wishlists.
	 */
	public function ajax_get_all_wishlists() {
		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$wishlists = $this->get_wishlists( true );

		// Cast DB string values to proper types for JavaScript.
		// $wpdb returns all values as strings — "0" is truthy in JS,
		// causing bugs like all wishlists showing as "Default".
		foreach ( $wishlists as $wl ) {
			$wl->id         = (int) $wl->id;
			$wl->is_default = (int) $wl->is_default;
			$wl->is_public  = (int) $wl->is_public;
			$wl->item_count = (int) $wl->item_count;
			$wl->sort_order = (int) $wl->sort_order;
		}

		wp_send_json_success(
			array(
				'wishlists'       => $wishlists,
				'max_wishlists'   => $this->get_max_wishlists(),
				'can_create_more' => count( $wishlists ) < $this->get_max_wishlists(),
				'sharing_enabled' => $this->is_sharing_enabled(),
			)
		);
	}

	/**
	 * AJAX: Move items between wishlists.
	 */
	public function ajax_move_items() {
		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$product_ids   = isset( $_POST['product_ids'] ) ? array_map( 'absint', (array) $_POST['product_ids'] ) : array();
		$from_wishlist = isset( $_POST['from_wishlist'] ) ? absint( $_POST['from_wishlist'] ) : 0;
		$to_wishlist   = isset( $_POST['to_wishlist'] ) ? absint( $_POST['to_wishlist'] ) : 0;

		$result = $this->move_items( $product_ids, $from_wishlist, $to_wishlist );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: Copy items between wishlists.
	 */
	public function ajax_copy_items() {
		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$product_ids   = isset( $_POST['product_ids'] ) ? array_map( 'absint', (array) $_POST['product_ids'] ) : array();
		$from_wishlist = isset( $_POST['from_wishlist'] ) ? absint( $_POST['from_wishlist'] ) : 0;
		$to_wishlist   = isset( $_POST['to_wishlist'] ) ? absint( $_POST['to_wishlist'] ) : 0;

		$result = $this->copy_items( $product_ids, $from_wishlist, $to_wishlist );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: Generate share link.
	 */
	public function ajax_generate_share_link() {
		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$wishlist_id = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : 0;

		$result = $this->generate_share_token( $wishlist_id );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * AJAX: View shared wishlist.
	 */
	public function ajax_view_shared_wishlist() {
		if ( ! $this->verify_ajax_nonce() ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$token = isset( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';

		$result = $this->get_shared_wishlist( $token );

		if ( $result ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( array( 'message' => __( 'Wishlist not found or is private.', 'ggm-commerce' ) ) );
		}
	}

	/**
	 * Create the wishlist database table.
	 * Called during plugin activation.
	 *
	 * @deprecated Use GGM_Commerce_Database::create_tables() instead.
	 */
	public static function create_table() {
		// Legacy method - tables are now created via GGM_Commerce_Database.
		$db = new GGM_Commerce_Database();
		$db->create_tables();
	}

	/**
	 * AJAX handler to get wishlist items as HTML for My Account display.
	 * Uses table layout similar to the Wishlist widget.
	 */
	public function ajax_get_wishlist_items_html() {
		$this->clean_ajax_output_buffer();

		// Verify user is logged in.
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( array( 'message' => __( 'You must be logged in.', 'ggm-commerce' ) ) );
		}

		// Verify nonce.
		if ( ! check_ajax_referer( 'ggm_commerce_nonce', 'nonce', false ) ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
		}

		$wishlist_id = isset( $_POST['wishlist_id'] ) ? absint( $_POST['wishlist_id'] ) : 0;
		if ( ! $wishlist_id ) {
			wp_send_json_error( array( 'message' => __( 'Invalid wishlist.', 'ggm-commerce' ) ) );
		}

		// Verify ownership.
		$wishlist = $this->get_wishlist( $wishlist_id );
		if ( ! $wishlist || (int) $wishlist->user_id !== get_current_user_id() ) {
			wp_send_json_error( array( 'message' => __( 'Wishlist not found.', 'ggm-commerce' ) ) );
		}

		// Get items - this returns enriched product objects with image_url and effective_price.
		$items = $this->get_items( $wishlist_id );

		// Get currency settings.
		$currency_options  = get_option( 'ggm_commerce_currency_options', array() );
		$currency_symbol   = isset( $currency_options['symbol'] ) ? $currency_options['symbol'] : '£';
		$currency_position = isset( $currency_options['position'] ) ? $currency_options['position'] : 'before';

		ob_start();

		if ( empty( $items ) ) {
			?>
			<div class="ggmc-wishlist-empty">
				<i class="eicon-heart-o"></i>
				<p><?php esc_html_e( 'This wishlist is empty.', 'ggm-commerce' ); ?></p>
				<p class="ggmc-wishlist-empty-hint"><?php esc_html_e( 'Browse products and add items to this wishlist.', 'ggm-commerce' ); ?></p>
			</div>
			<?php
		} else {
			?>
			<table class="ggmc-wishlist-table ggmc-account-wishlist-table">
				<thead>
					<tr>
						<th class="wishlist-col-remove"></th>
						<th class="wishlist-col-image"><?php esc_html_e( 'Image', 'ggm-commerce' ); ?></th>
						<th class="wishlist-col-name"><?php esc_html_e( 'Product', 'ggm-commerce' ); ?></th>
						<th class="wishlist-col-price"><?php esc_html_e( 'Price', 'ggm-commerce' ); ?></th>
						<th class="wishlist-col-stock"><?php esc_html_e( 'Stock', 'ggm-commerce' ); ?></th>
						<th class="wishlist-col-actions"></th>
					</tr>
				</thead>
				<tbody>
					<?php foreach ( $items as $product ) : ?>
						<tr class="ggmc-wishlist-item" data-product-id="<?php echo esc_attr( $product->id ); ?>">
							<td class="wishlist-col-remove">
								<button type="button" class="ggmc-wishlist-remove btn-remove-from-wishlist"
									data-product-id="<?php echo esc_attr( $product->id ); ?>"
									data-wishlist-id="<?php echo esc_attr( $wishlist_id ); ?>"
									title="<?php esc_attr_e( 'Remove from wishlist', 'ggm-commerce' ); ?>">
									<i class="eicon-close"></i>
								</button>
							</td>
							<td class="wishlist-col-image">
								<?php if ( ! empty( $product->image_url ) ) : ?>
									<a href="<?php echo esc_url( home_url( '/product-details/' . $product->slug ) ); ?>">
										<img src="<?php echo esc_url( $product->image_url ); ?>"
											alt="<?php echo esc_attr( $product->name ); ?>"
											class="wishlist-product-image">
									</a>
								<?php else : ?>
									<div class="wishlist-no-image">
										<i class="eicon-image-bold"></i>
									</div>
								<?php endif; ?>
							</td>
							<td class="wishlist-col-name">
								<a href="<?php echo esc_url( home_url( '/product-details/' . $product->slug ) ); ?>" class="wishlist-product-name">
									<?php echo esc_html( $product->name ); ?>
								</a>
								<?php if ( ! empty( $product->sku ) ) : ?>
									<span class="wishlist-product-sku"><?php echo esc_html( 'SKU: ' . $product->sku ); ?></span>
								<?php endif; ?>
							</td>
							<td class="wishlist-col-price">
								<?php
								$formatted_price = 'before' === $currency_position
									? $currency_symbol . number_format( (float) $product->effective_price, 2 )
									: number_format( (float) $product->effective_price, 2 ) . $currency_symbol;
								echo esc_html( $formatted_price );
								?>
								<?php if ( $product->sale_price && $product->sale_price < $product->price ) : ?>
									<del class="wishlist-original-price">
										<?php
										$formatted_original = 'before' === $currency_position
											? $currency_symbol . number_format( (float) $product->price, 2 )
											: number_format( (float) $product->price, 2 ) . $currency_symbol;
										echo esc_html( $formatted_original );
										?>
									</del>
								<?php endif; ?>
							</td>
							<td class="wishlist-col-stock">
								<?php
								$stock_status = isset( $product->stock_status ) ? $product->stock_status : 'instock';
								$stock_class  = 'outofstock' === $stock_status ? 'out-of-stock' : 'in-stock';
								$stock_text   = 'outofstock' === $stock_status
									? __( 'Out of Stock', 'ggm-commerce' )
									: __( 'In Stock', 'ggm-commerce' );
								?>
								<span class="wishlist-stock-badge <?php echo esc_attr( $stock_class ); ?>">
									<?php echo esc_html( $stock_text ); ?>
								</span>
							</td>
							<td class="wishlist-col-actions">
								<button type="button" class="ggmc-add-to-cart-btn btn-add-to-cart-from-wishlist"
									data-product-id="<?php echo esc_attr( $product->id ); ?>"
									<?php echo 'outofstock' === $stock_status ? 'disabled' : ''; ?>>
									<i class="fas fa-shopping-cart" aria-hidden="true"></i>
									<span><?php esc_html_e( 'Add to Cart', 'ggm-commerce' ); ?></span>
								</button>
							</td>
						</tr>
					<?php endforeach; ?>
				</tbody>
			</table>
			<?php
		}

		$html = ob_get_clean();

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

	/**
	 * Output the wishlist selector popover HTML.
	 * This is a global element used when adding products to wishlists.
	 */
	public function output_wishlist_selector_popover() {
		// Only output for logged-in users when wishlist premium is active.
		if ( ! is_user_logged_in() ) {
			return;
		}

		// Check if wishlist premium feature is activated.
		if ( ! class_exists( 'GGM_Commerce_License' ) ) {
			return;
		}
		$license = GGM_Commerce_License::instance();
		if ( ! $license->is_widget_activated( 'wishlist' ) ) {
			return;
		}

		$wishlists     = $this->get_wishlists( true );
		$max_wishlists = $this->get_max_wishlists();
		$can_create    = count( $wishlists ) < $max_wishlists;
		?>
		<!-- Wishlist Selector Popover -->
		<div id="ggmc-wishlist-selector-popover" class="ggmc-wishlist-selector-popover" style="display: none;">
			<div class="ggmc-wishlist-popover-arrow"></div>
			<div class="ggmc-wishlist-popover-content">
				<div class="ggmc-wishlist-popover-header">
					<span class="ggmc-wishlist-popover-title"><?php esc_html_e( 'Add to Wishlist', 'ggm-commerce' ); ?></span>
					<button type="button" class="ggmc-wishlist-popover-close" aria-label="<?php esc_attr_e( 'Close', 'ggm-commerce' ); ?>">
						<i class="eicon-close"></i>
					</button>
				</div>
				<div class="ggmc-wishlist-popover-body">
					<div class="ggmc-wishlist-popover-list">
						<?php if ( ! empty( $wishlists ) ) : ?>
							<?php foreach ( $wishlists as $wishlist ) : ?>
								<label class="ggmc-wishlist-popover-item" data-wishlist-id="<?php echo esc_attr( $wishlist->id ); ?>">
									<input type="radio" name="ggmc_wishlist_select" value="<?php echo esc_attr( $wishlist->id ); ?>"
										<?php checked( $wishlist->is_default ); ?> />
									<span class="ggmc-wishlist-popover-item-name">
										<?php echo esc_html( $wishlist->name ); ?>
										<?php if ( $wishlist->is_default ) : ?>
											<span class="ggmc-default-indicator"><?php esc_html_e( '(Default)', 'ggm-commerce' ); ?></span>
										<?php endif; ?>
									</span>
									<span class="ggmc-wishlist-popover-item-count"><?php echo esc_html( $wishlist->item_count ); ?></span>
								</label>
							<?php endforeach; ?>
						<?php else : ?>
							<p class="ggmc-wishlist-popover-empty"><?php esc_html_e( 'No wishlists yet.', 'ggm-commerce' ); ?></p>
						<?php endif; ?>
					</div>

					<?php if ( $can_create ) : ?>
						<div class="ggmc-wishlist-popover-create">
							<button type="button" class="ggmc-wishlist-popover-create-btn">
								<i class="eicon-plus-circle-o"></i>
								<?php esc_html_e( 'Create New Wishlist', 'ggm-commerce' ); ?>
							</button>
							<div class="ggmc-wishlist-popover-create-form" style="display: none;">
								<input type="text" class="ggmc-wishlist-popover-new-name"
									placeholder="<?php esc_attr_e( 'Wishlist name...', 'ggm-commerce' ); ?>"
									maxlength="100" />
								<div class="ggmc-wishlist-popover-create-actions">
									<button type="button" class="ggmc-wishlist-popover-create-cancel">
										<?php esc_html_e( 'Cancel', 'ggm-commerce' ); ?>
									</button>
									<button type="button" class="ggmc-wishlist-popover-create-confirm">
										<?php esc_html_e( 'Create & Add', 'ggm-commerce' ); ?>
									</button>
								</div>
							</div>
						</div>
					<?php endif; ?>
				</div>
				<div class="ggmc-wishlist-popover-footer">
					<button type="button" class="ggmc-wishlist-popover-add-btn" disabled>
						<?php esc_html_e( 'Add to Wishlist', 'ggm-commerce' ); ?>
					</button>
				</div>
			</div>
		</div>
		<?php
	}
}
