/**
 * FoodOrd Product Modal Footer JavaScript
 *
 * @package FoodOrd
 * @since 1.0
 */

(function ($) {
	'use strict';

	const I18N = (typeof window.foodordModalFooterI18n === 'object' && window.foodordModalFooterI18n !== null)
		? window.foodordModalFooterI18n
		: {};

	const getI18nString = (key) => (typeof I18N[key] === 'string') ? I18N[key] : '';
	const escapeHtml = (value) => $('<div></div>').text(value || '').html();
	const getCheckoutLabel = () => {
		if (typeof foodord_modal_vars !== 'undefined' && typeof foodord_modal_vars.checkout_btn_text === 'string') {
			return foodord_modal_vars.checkout_btn_text;
		}
		return getI18nString('checkout');
	};
	const buildCtaHtml = (count, totalHtml) => {
		const checkoutLabel = escapeHtml(getCheckoutLabel());
		const itemsLabel = escapeHtml(getI18nString('itemsInCart'));
		const countHtml = escapeHtml(String(count));
		const itemsAttr = itemsLabel ? ' aria-label="' + itemsLabel + '"' : '';
		return '<span class="wr-card__cta-left"><span class="wr-card__cta-count"' + itemsAttr + '>' + countHtml + '</span><span class="wr-card__cta-label">' + checkoutLabel + '</span></span><span class="wr-card__cta-total">' + totalHtml + '</span>';
	};
	const buildAddToCartLabel = () => {
		return escapeHtml(getI18nString('addToCart'));
	};
	const buildAddingStatusLabel = () => {
		const label = getI18nString('adding');
		return escapeHtml(label || 'Adding…');
	};
	const buildAddToCartLoadingHtml = () => {
		const statusLabel = buildAddingStatusLabel();
		return '<span class="foodord-add-to-cart-spinner" aria-hidden="true"></span><span class="screen-reader-text">' + statusLabel + '</span>';
	};
	const buildEditLabel = (name) => {
		const template = getI18nString('editItem');
		const normalizedName = typeof name === 'string' ? name : '';
		if (template) {
			if (template.indexOf('%s') !== -1) {
				return template.replace('%s', normalizedName);
			}
			return (template + ' ' + normalizedName).trim();
		}
		return ('Edit ' + normalizedName).trim();
	};

	if (typeof window.FoodordGetLazyPlaceholder !== 'function') {
		window.FoodordGetLazyPlaceholder = function (imageUrl) {
			const placeholder = (typeof window.FOODORD_LAZY_PLACEHOLDER !== 'undefined') ? window.FOODORD_LAZY_PLACEHOLDER : '';
			if (placeholder && placeholder.length) {
				return placeholder;
			}
			return imageUrl || '';
		};
	}

	const parseToggleValue = (value) => {
		if (value === true || value === 'yes' || value === 'true' || value === 1 || value === '1') {
			return true;
		}
		if (value === false || value === 'no' || value === 'false' || value === 0 || value === '0') {
			return false;
		}
		return Boolean(value);
	};

	let showToppingGroupLabels = true;
	const QUANTITY_STORAGE_PREFIX = 'foodord_modal_qty_';

	const setShowToppingGroupLabels = (value) => {
		showToppingGroupLabels = parseToggleValue(value);
		window.FoodordShowToppingGroupLabels = showToppingGroupLabels;
	};

	if (typeof foodord_modal_vars !== 'undefined' && Object.prototype.hasOwnProperty.call(foodord_modal_vars, 'show_topping_group_labels')) {
		setShowToppingGroupLabels(foodord_modal_vars.show_topping_group_labels);
	}

	window.FoodordShowToppingGroupLabels = showToppingGroupLabels;

	/**
	 * Modal Footer Functionality
	 */
	class FoodOrdModalFooter {
		constructor(modalInstance) {
			this.modal = modalInstance;
			this.$modal = modalInstance.modal;
			this._quantityRestoreTimer = null;
			this._pendingQuantityRestore = false;
			this._quantityRestoreAttempts = 0;
			this._lastFoundVariationId = 0;
			this._preventAutoRestore = false;
			this._prefillTimer = null;
			this.prefillData = null;
			this.isEditing = false;
			this.editingCartItemKey = '';
			this.originalEditingSignature = '';
			this.defaultAddToCartLabel = '';
			FoodOrdModalFooter.ensureGlobalListeners();
			this.init();
		}

		init() {
			// Will be initialized when modal content loads
		}

		/**
		 * Initialize footer controls when modal content is loaded
		 */
		initFooterControls() {
			this.initQuantityControls();
			this.initAddToCartButton();
			this.initToppingListeners();
			this.initVariationValidation();
			// Initialize CTA state on load
			this.updateAddToCartCta();

			// Listen toppings price updates and recompute CTA
			$(document)
				.off('foodord_toppings_price_updated.modalFooter')
				.on('foodord_toppings_price_updated.modalFooter', () => {
					this.updateAddToCartCta();
				});

			// Listen for WooCommerce variation changes
			this.$modal.off('found_variation.modalFooter reset_data.modalFooter');
			this.$modal.on('found_variation.modalFooter', '.variations_form', (e, variation) => {
				if (variation && typeof variation.display_price !== 'undefined') {
					const price = parseFloat(variation.display_price);
					const $btn = this.$modal.find('.foodord-modal-footer .foodord-add-to-cart-btn');
					if ($btn.length && !isNaN(price)) {
						// Store original unit price if not already stored
						if (!$btn.data('unit-price-original')) {
							$btn.data('unit-price-original', $btn.data('unit-price') || 0);
						}
						// Update base price but maintain toppings calculation
						$btn.data('unit-price-original', price);
						this.updateAddToCartCta();
					}
				}

				const variationIdFromEvent = variation && typeof variation.variation_id !== 'undefined' ? parseInt(variation.variation_id, 10) : 0;
				this._lastFoundVariationId = Number.isNaN(variationIdFromEvent) ? 0 : variationIdFromEvent;
				this.restoreQuantityForCurrentSelection(null, this._lastFoundVariationId);
			});

			this.$modal.on('reset_data.modalFooter', '.variations_form', () => {
				const $btn = this.$modal.find('.foodord-modal-footer .foodord-add-to-cart-btn');
				if ($btn.length) {
					const initial = parseFloat($btn.data('unit-price-initial'));
					$btn.data('unit-price-original', isNaN(initial) ? 0 : initial);
					this.updateAddToCartCta();
				}

				this._lastFoundVariationId = 0;
				this.restoreQuantityForCurrentSelection();
			});
		}

		hasVariations() {
			return this.$modal.find('.variations_form').length > 0;
		}

		schedulePendingQuantityRestore() {
			if (this._quantityRestoreTimer) {
				clearTimeout(this._quantityRestoreTimer);
			}
			this._quantityRestoreTimer = setTimeout(() => {
				this._quantityRestoreTimer = null;
				this.restoreQuantityForCurrentSelection();
			}, 150);
		}

		queueQuantityRestore() {
			this._pendingQuantityRestore = true;
			if (typeof this._quantityRestoreAttempts !== 'number') {
				this._quantityRestoreAttempts = 0;
			}
			if (this._quantityRestoreAttempts > 20) {
				return;
			}
			this._quantityRestoreAttempts += 1;
			this.schedulePendingQuantityRestore();
		}

		clearEditingState() {
			this.prefillData = null;
			this.isEditing = false;
			this.editingCartItemKey = '';
			this.originalEditingSignature = '';
			if (this._prefillTimer) {
				clearTimeout(this._prefillTimer);
				this._prefillTimer = null;
			}

			const $btn = this.$modal.find('.foodord-modal-footer .foodord-add-to-cart-btn');
			const $label = $btn.find('.foodord-add-to-cart-label');
			if ($btn.length) {
				$btn.removeAttr('data-editing');
				$btn.removeData('editing-cart-item-key');
				$btn.data('editing-cart-item-key', '');
			}
			if ($label.length) {
				const labelText = this.defaultAddToCartLabel || buildAddToCartLabel();
				if (labelText) {
					$label.text(labelText);
					this.defaultAddToCartLabel = labelText;
				}
			}
		}

		setPrefillData(prefillData) {
			if (this._prefillTimer) {
				clearTimeout(this._prefillTimer);
				this._prefillTimer = null;
			}

			const safeData = prefillData && typeof prefillData === 'object' ? prefillData : null;
			if (!safeData) {
				this.clearEditingState();
				return;
			}

			this.prefillData = $.extend(true, {}, safeData);
			this.isEditing = !!(this.prefillData && this.prefillData.cart_item_key);
			this.editingCartItemKey = this.isEditing ? String(this.prefillData.cart_item_key) : '';
			this.originalEditingSignature = this.prefillData && typeof this.prefillData.toppings_signature === 'string' ? this.prefillData.toppings_signature : '';

			const $btn = this.$modal.find('.foodord-modal-footer .foodord-add-to-cart-btn');
			const $label = $btn.find('.foodord-add-to-cart-label');
			if ($label.length && !this.defaultAddToCartLabel) {
				const labelText = buildAddToCartLabel() || $label.text();
				this.defaultAddToCartLabel = labelText;
				if (labelText) {
					$label.text(labelText);
				}
			}

			if ($btn.length) {
				if (this.isEditing) {
					$btn.attr('data-editing', '1');
					$btn.data('editing-cart-item-key', this.editingCartItemKey);
					if ($label.length) {
						$label.text(getI18nString('updateItem'));
					}
				} else {
					$btn.removeAttr('data-editing');
					$btn.removeData('editing-cart-item-key');
					$btn.data('editing-cart-item-key', '');
					if ($label.length) {
						const labelText = this.defaultAddToCartLabel || buildAddToCartLabel();
						if (labelText) {
							$label.text(labelText);
							this.defaultAddToCartLabel = labelText;
						}
					}
				}
			}

			if (!this.isEditing) {
				this.clearAllToppingSelections(false);
				this.updateAddToCartCta();
				return;
			}

			this._prefillTimer = setTimeout(() => {
				this._prefillTimer = null;
				this.applyPrefillSelections();
			}, 20);
		}

		applyPrefillSelections() {
			if (!this.prefillData || !this.isEditing) {
				return;
			}

			this._preventAutoRestore = true;
			this._pendingQuantityRestore = false;
			this._quantityRestoreAttempts = 0;

			const productId = parseInt(this.$modal.find('.foodord-add-to-cart-btn').data('product-id'), 10) || 0;
			const quantity = parseInt(this.prefillData.quantity, 10);
			if (!Number.isNaN(quantity) && quantity > 0) {
				const $quantityInput = this.$modal.find('#foodord-quantity-input');
				if ($quantityInput.length) {
					$quantityInput.val(quantity).trigger('change');
				}
			}

			// Variation attributes.
			if (this.prefillData.attributes && typeof this.prefillData.attributes === 'object') {
				Object.keys(this.prefillData.attributes).forEach((key) => {
					const value = this.prefillData.attributes[key];
					const sanitizedKey = String(key);
					const sanitizedValue = typeof value === 'string' ? value : '';
					if ('' === sanitizedKey) {
						return;
					}

					let targetSelectId = '';
					const $select = this.$modal.find('.variations select[name="' + sanitizedKey + '"]');
					if ($select.length) {
						targetSelectId = $select.attr('id') || '';
						if ($select.val() !== sanitizedValue) {
							$select.val(sanitizedValue).trigger('change');
						} else {
							$select.trigger('change');
						}
					}

					let $radio = $();
					if (targetSelectId) {
						$radio = this.$modal.find('.foodord-attr-input[data-target-select="#' + targetSelectId + '"][value="' + sanitizedValue + '"]');
					}
					if (!$radio.length) {
						$radio = this.$modal.find('.foodord-attr-input[name="' + sanitizedKey + '"][value="' + sanitizedValue + '"]');
					}
					if ($radio.length) {
						$radio.prop('checked', true).trigger('change');
						$radio.closest('.foodord-attr-option').addClass('is-selected');
					}
				});
			}

			if (this.prefillData.variation_id) {
				const parsedVar = parseInt(this.prefillData.variation_id, 10);
				if (!Number.isNaN(parsedVar) && parsedVar > 0) {
					this._lastFoundVariationId = parsedVar;
					this.$modal.find('input[name="variation_id"]').val(parsedVar);
				}
			}

			this.clearAllToppingSelections(false);

			if (Array.isArray(this.prefillData.toppings)) {
				this.prefillData.toppings.forEach((set) => {
					if (!set || typeof set !== 'object') {
						return;
					}
					const setId = set.set_id ? String(set.set_id) : '';
					if ('' === setId) {
						return;
					}
					const groupType = set.group_type ? String(set.group_type) : '';
					const selections = Array.isArray(set.items) ? set.items.map((item) => String(item)) : [];
					if ('radio' === groupType) {
						selections.forEach((value) => {
							const $input = this.$modal.find('.foodord-product-toppings__input[type="radio"][name="foodord_toppings[' + setId + ']"][value="' + value + '"]');
							if ($input.length) {
								$input.prop('checked', true).trigger('change');
								$input.closest('.foodord-product-toppings__option').addClass('is-selected');
							}
						});
					} else if ('checkbox' === groupType) {
						selections.forEach((value) => {
							const $checkbox = this.$modal.find('.foodord-product-toppings__input[type="checkbox"][name="foodord_toppings[' + setId + '][]"][value="' + value + '"]');
							if ($checkbox.length) {
								$checkbox.prop('checked', true).trigger('change');
							}
						});
					} else {
						const $select = this.$modal.find('select[name="foodord_toppings[' + setId + ']"]');
						if ($select.length) {
							const targetValue = selections.length ? selections[0] : '';
							$select.val(targetValue).trigger('change');
						}
					}
				});
			}

			this._preventAutoRestore = false;
			this.updateAddToCartCta();
			if (productId && quantity && this.prefillData) {
				this.persistQuantityPreference(productId, this._lastFoundVariationId || 0, quantity, this.prefillData.toppings_signature || '');
			}
		}

		clearAllToppingSelections(triggerChange = true) {
			const shouldTrigger = Boolean(triggerChange);
			const $selects = this.$modal.find('.foodord-product-toppings__select');
			$selects.each(function () {
				const $select = $(this);
				if ($select.val() !== '') {
					$select.val('');
					if (shouldTrigger) {
						$select.trigger('change');
					}
				}
			});

			const $inputs = this.$modal.find('.foodord-product-toppings__input');
			$inputs.each(function () {
				const $input = $(this);
				if ($input.prop('checked')) {
					$input.prop('checked', false);
					if (shouldTrigger) {
						$input.trigger('change');
					}
				}
				if ($input.attr('type') === 'checkbox') {
					$input.prop('disabled', false);
				}
				$input.closest('.foodord-product-toppings__option').removeClass('is-selected is-checked');
			});

			this.$modal.find('.foodord-product-toppings__set[data-group-type="checkbox"]')
				.removeClass('checkbox-at-min checkbox-at-max checkbox-near-max');

			if (shouldTrigger) {
				this.updateAddToCartCta();
			}
		}

		static ensureGlobalListeners() {
			if (FoodOrdModalFooter._listenersReady) {
				return;
			}

			if (typeof document !== 'undefined') {
				document.addEventListener('foodord_cart_updated', FoodOrdModalFooter.handleCartUpdated);
			}

			FoodOrdModalFooter._listenersReady = true;
		}

		static handleCartUpdated(event) {
			try {
				const detail = event && event.detail ? event.detail : null;
				if (!detail) {
					return;
				}

				if (Array.isArray(detail.cart_items)) {
					FoodOrdModalFooter.setCartSnapshot(detail.cart_items);
				}

				let cartCount = null;
				if (Array.isArray(detail.cart_items)) {
					cartCount = detail.cart_items.length;
				} else if (typeof detail.cart_contents_count !== 'undefined') {
					const parsed = parseInt(detail.cart_contents_count, 10);
					if (!Number.isNaN(parsed)) {
						cartCount = parsed;
					}
				}

				if (cartCount === null && typeof detail.cart_count !== 'undefined') {
					const parsedCount = parseInt(detail.cart_count, 10);
					if (!Number.isNaN(parsedCount)) {
						cartCount = parsedCount;
					}
				}

				if (cartCount === null && typeof detail.cart_hash === 'string' && detail.cart_hash === '') {
					cartCount = 0;
				}

				if (cartCount === null && typeof detail.cart_total_html === 'string' && detail.cart_total_html.trim() === '0') {
					cartCount = 0;
				}

				if (cartCount === null && Array.isArray(FoodOrdModalFooter.cartSnapshot) && FoodOrdModalFooter.cartSnapshot.length > 0) {
					cartCount = FoodOrdModalFooter.cartSnapshot.length;
				}

				if (cartCount !== null && cartCount > 0) {
					FoodOrdModalFooter.syncOpenModalsWithCart();
				}

				if (cartCount === 0) {
					FoodOrdModalFooter.clearAllStoredQuantities();
					FoodOrdModalFooter.resetOpenModalsQuantity();
				}
			} catch (_err) {
				void _err;
				// Ignore listener errors silently.
			}
		}

		static clearAllStoredQuantities() {
			FoodOrdModalFooter.quantityMemory = {};
			FoodOrdModalFooter.cartSnapshot = [];

			try {
				if (typeof window !== 'undefined' && window.localStorage) {
					const keysToRemove = [];
					for (let i = 0; i < window.localStorage.length; i += 1) {
						const keyName = window.localStorage.key(i);
						if (keyName && keyName.indexOf(QUANTITY_STORAGE_PREFIX) === 0) {
							keysToRemove.push(keyName);
						}
					}
					keysToRemove.forEach((key) => window.localStorage.removeItem(key));
				}
			} catch (_err) {
				void _err;
				// Ignore storage cleanup errors.
			}

			try {
				if (typeof document !== 'undefined' && document.cookie) {
					const cookies = document.cookie.split(';');
					cookies.forEach((cookieString) => {
						const trimmed = cookieString.trim();
						if (trimmed.indexOf(QUANTITY_STORAGE_PREFIX) === 0) {
							const name = trimmed.split('=')[0];
							document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
						}
					});
				}
			} catch (_err) {
				void _err;
				// Ignore cookie cleanup errors.
			}
		}

		static resetOpenModalsQuantity() {
			try {
				if (typeof window === 'undefined' || typeof window.jQuery === 'undefined') {
					return;
				}
				const $ = window.jQuery;
				$('.foodord-modal-footer #foodord-quantity-input').each(function () {
					const $input = $(this);
					$input.val(1).trigger('change');
				});
			} catch (_err) {
				void _err;
				// Ignore modal reset errors silently.
			}
		}

		static syncOpenModalsWithCart() {
			if (typeof window === 'undefined' || typeof window.jQuery === 'undefined') {
				return;
			}
			const $ = window.jQuery;
			$('.foodord-modal:visible').each(function () {
				const footerInstance = $(this).data('footerInstance');
				if (footerInstance && typeof footerInstance.restoreQuantityForCurrentSelection === 'function') {
					footerInstance.restoreQuantityForCurrentSelection();
				}
			});
		}

		static setCartSnapshot(items) {
			if (!Array.isArray(items)) {
				FoodOrdModalFooter.cartSnapshot = [];
				return;
			}
			FoodOrdModalFooter.cartSnapshot = items.map((item) => {
				const productId = parseInt(item && (item.product_id || item.id), 10) || 0;
				const variationId = parseInt(item && item.variation_id, 10) || 0;
				const quantity = parseInt(item && item.quantity, 10) || 0;
				const signature = item && typeof item.toppings_signature === 'string' ? item.toppings_signature : '';
				const cartItemKey = item && typeof item.cart_item_key === 'string' ? item.cart_item_key : '';
				return {
					product_id: productId,
					variation_id: variationId,
					quantity: quantity,
					toppings_signature: signature,
					cart_item_key: cartItemKey
				};
			});
		}

		static findMatchingCartEntry(productId, variationId, signature) {
			if (!Array.isArray(FoodOrdModalFooter.cartSnapshot)) {
				return null;
			}
			const targetProduct = parseInt(productId, 10) || 0;
			const targetVariation = parseInt(variationId, 10) || 0;
			const targetSignature = typeof signature === 'string' ? signature : '';

			for (let i = 0; i < FoodOrdModalFooter.cartSnapshot.length; i += 1) {
				const entry = FoodOrdModalFooter.cartSnapshot[i];
				if (!entry) {
					continue;
				}
				if (entry.product_id === targetProduct && entry.variation_id === targetVariation && entry.toppings_signature === targetSignature) {
					return {
						quantity: entry.quantity,
						cart_item_key: entry.cart_item_key || '',
						signature: entry.toppings_signature
					};
				}
			}

			return null;
		}

		static md5(string) {
			const rotateLeft = function (lValue, iShiftBits) {
				return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
			};

			const addUnsigned = function (lX, lY) {
				const lX4 = lX & 0x40000000;
				const lY4 = lY & 0x40000000;
				const lX8 = lX & 0x80000000;
				const lY8 = lY & 0x80000000;
				const lResult = (lX & 0x3fffffff) + (lY & 0x3fffffff);
				if (lX4 & lY4) {
					return lResult ^ 0x80000000 ^ lX8 ^ lY8;
				}
				if (lX4 | lY4) {
					if (lResult & 0x40000000) {
						return lResult ^ 0xc0000000 ^ lX8 ^ lY8;
					}
					return lResult ^ 0x40000000 ^ lX8 ^ lY8;
				}
				return lResult ^ lX8 ^ lY8;
			};

			const _F = function (x, y, z) { return (x & y) | ((~x) & z); };
			const _G = function (x, y, z) { return (x & z) | (y & (~z)); };
			const _H = function (x, y, z) { return x ^ y ^ z; };
			const _I = function (x, y, z) { return y ^ (x | (~z)); };

			const _FF = function (a, b, c, d, x, s, ac) {
				a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
				return addUnsigned(rotateLeft(a, s), b);
			};

			const _GG = function (a, b, c, d, x, s, ac) {
				a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
				return addUnsigned(rotateLeft(a, s), b);
			};

			const _HH = function (a, b, c, d, x, s, ac) {
				a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
				return addUnsigned(rotateLeft(a, s), b);
			};

			const _II = function (a, b, c, d, x, s, ac) {
				a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
				return addUnsigned(rotateLeft(a, s), b);
			};

			const convertToWordArray = function (str) {
				let lWordCount;
				const lMessageLength = str.length;
				const lNumberOfWordsTemp1 = lMessageLength + 8;
				const lNumberOfWordsTemp2 = (lNumberOfWordsTemp1 - (lNumberOfWordsTemp1 % 64)) / 64;
				const lNumberOfWords = (lNumberOfWordsTemp2 + 1) * 16;
				const lWordArray = new Array(lNumberOfWords - 1);
				let lBytePosition = 0;
				let lByteCount = 0;

				while (lByteCount < lMessageLength) {
					lWordCount = (lByteCount - (lByteCount % 4)) / 4;
					lBytePosition = (lByteCount % 4) * 8;
					lWordArray[lWordCount] = (lWordArray[lWordCount] || 0) | (str.charCodeAt(lByteCount) << lBytePosition);
					lByteCount += 1;
				}

				lWordCount = (lByteCount - (lByteCount % 4)) / 4;
				lBytePosition = (lByteCount % 4) * 8;
				lWordArray[lWordCount] = lWordArray[lWordCount] || 0;
				lWordArray[lWordCount] |= 0x80 << lBytePosition;
				lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
				lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
				return lWordArray;
			};

			const wordToHex = function (lValue) {
				let wordToHexValue = '';
				for (let lCount = 0; lCount <= 3; lCount += 1) {
					const lByte = (lValue >>> (lCount * 8)) & 255;
					const wordToHexValueTemp = '0' + lByte.toString(16);
					wordToHexValue += wordToHexValueTemp.slice(-2);
				}
				return wordToHexValue;
			};

			const utf8Encode = function (stringValue) {
				try {
					return decodeURIComponent(encodeURIComponent(stringValue));
				} catch (_err) {
					void _err;
					return stringValue;
				}
			};

			let x = [];
			let k;
			let AA;
			let BB;
			let CC;
			let DD;
			let a;
			let b;
			let c;
			let d;

			const S11 = 7;
			const S12 = 12;
			const S13 = 17;
			const S14 = 22;
			const S21 = 5;
			const S22 = 9;
			const S23 = 14;
			const S24 = 20;
			const S31 = 4;
			const S32 = 11;
			const S33 = 16;
			const S34 = 23;
			const S41 = 6;
			const S42 = 10;
			const S43 = 15;
			const S44 = 21;

			string = utf8Encode(string);
			x = convertToWordArray(string);

			a = 0x67452301;
			b = 0xefcdab89;
			c = 0x98badcfe;
			d = 0x10325476;

			for (k = 0; k < x.length; k += 16) {
				AA = a;
				BB = b;
				CC = c;
				DD = d;
				a = _FF(a, b, c, d, x[k + 0], S11, 0xd76aa478);
				d = _FF(d, a, b, c, x[k + 1], S12, 0xe8c7b756);
				c = _FF(c, d, a, b, x[k + 2], S13, 0x242070db);
				b = _FF(b, c, d, a, x[k + 3], S14, 0xc1bdceee);
				a = _FF(a, b, c, d, x[k + 4], S11, 0xf57c0faf);
				d = _FF(d, a, b, c, x[k + 5], S12, 0x4787c62a);
				c = _FF(c, d, a, b, x[k + 6], S13, 0xa8304613);
				b = _FF(b, c, d, a, x[k + 7], S14, 0xfd469501);
				a = _FF(a, b, c, d, x[k + 8], S11, 0x698098d8);
				d = _FF(d, a, b, c, x[k + 9], S12, 0x8b44f7af);
				c = _FF(c, d, a, b, x[k + 10], S13, 0xffff5bb1);
				b = _FF(b, c, d, a, x[k + 11], S14, 0x895cd7be);
				a = _FF(a, b, c, d, x[k + 12], S11, 0x6b901122);
				d = _FF(d, a, b, c, x[k + 13], S12, 0xfd987193);
				c = _FF(c, d, a, b, x[k + 14], S13, 0xa679438e);
				b = _FF(b, c, d, a, x[k + 15], S14, 0x49b40821);
				a = _GG(a, b, c, d, x[k + 1], S21, 0xf61e2562);
				d = _GG(d, a, b, c, x[k + 6], S22, 0xc040b340);
				c = _GG(c, d, a, b, x[k + 11], S23, 0x265e5a51);
				b = _GG(b, c, d, a, x[k + 0], S24, 0xe9b6c7aa);
				a = _GG(a, b, c, d, x[k + 5], S21, 0xd62f105d);
				d = _GG(d, a, b, c, x[k + 10], S22, 0x2441453);
				c = _GG(c, d, a, b, x[k + 15], S23, 0xd8a1e681);
				b = _GG(b, c, d, a, x[k + 4], S24, 0xe7d3fbc8);
				a = _GG(a, b, c, d, x[k + 9], S21, 0x21e1cde6);
				d = _GG(d, a, b, c, x[k + 14], S22, 0xc33707d6);
				c = _GG(c, d, a, b, x[k + 3], S23, 0xf4d50d87);
				b = _GG(b, c, d, a, x[k + 8], S24, 0x455a14ed);
				a = _GG(a, b, c, d, x[k + 13], S21, 0xa9e3e905);
				d = _GG(d, a, b, c, x[k + 2], S22, 0xfcefa3f8);
				c = _GG(c, d, a, b, x[k + 7], S23, 0x676f02d9);
				b = _GG(b, c, d, a, x[k + 12], S24, 0x8d2a4c8a);
				a = _HH(a, b, c, d, x[k + 5], S31, 0xfffa3942);
				d = _HH(d, a, b, c, x[k + 8], S32, 0x8771f681);
				c = _HH(c, d, a, b, x[k + 11], S33, 0x6d9d6122);
				b = _HH(b, c, d, a, x[k + 14], S34, 0xfde5380c);
				a = _HH(a, b, c, d, x[k + 1], S31, 0xa4beea44);
				d = _HH(d, a, b, c, x[k + 4], S32, 0x4bdecfa9);
				c = _HH(c, d, a, b, x[k + 7], S33, 0xf6bb4b60);
				b = _HH(b, c, d, a, x[k + 10], S34, 0xbebfbc70);
				a = _HH(a, b, c, d, x[k + 13], S31, 0x289b7ec6);
				d = _HH(d, a, b, c, x[k + 0], S32, 0xeaa127fa);
				c = _HH(c, d, a, b, x[k + 3], S33, 0xd4ef3085);
				b = _HH(b, c, d, a, x[k + 6], S34, 0x4881d05);
				a = _HH(a, b, c, d, x[k + 9], S31, 0xd9d4d039);
				d = _HH(d, a, b, c, x[k + 12], S32, 0xe6db99e5);
				c = _HH(c, d, a, b, x[k + 15], S33, 0x1fa27cf8);
				b = _HH(b, c, d, a, x[k + 2], S34, 0xc4ac5665);
				a = _II(a, b, c, d, x[k + 0], S41, 0xf4292244);
				d = _II(d, a, b, c, x[k + 7], S42, 0x432aff97);
				c = _II(c, d, a, b, x[k + 14], S43, 0xab9423a7);
				b = _II(b, c, d, a, x[k + 5], S44, 0xfc93a039);
				a = _II(a, b, c, d, x[k + 12], S41, 0x655b59c3);
				d = _II(d, a, b, c, x[k + 3], S42, 0x8f0ccc92);
				c = _II(c, d, a, b, x[k + 10], S43, 0xffeff47d);
				b = _II(b, c, d, a, x[k + 1], S44, 0x85845dd1);
				a = _II(a, b, c, d, x[k + 8], S41, 0x6fa87e4f);
				d = _II(d, a, b, c, x[k + 15], S42, 0xfe2ce6e0);
				c = _II(c, d, a, b, x[k + 6], S43, 0xa3014314);
				b = _II(b, c, d, a, x[k + 13], S44, 0x4e0811a1);
				a = _II(a, b, c, d, x[k + 4], S41, 0xf7537e82);
				d = _II(d, a, b, c, x[k + 11], S42, 0xbd3af235);
				c = _II(c, d, a, b, x[k + 2], S43, 0x2ad7d2bb);
				b = _II(b, c, d, a, x[k + 9], S44, 0xeb86d391);
				a = addUnsigned(a, AA);
				b = addUnsigned(b, BB);
				c = addUnsigned(c, CC);
				d = addUnsigned(d, DD);
			}

			const temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
			return temp.toLowerCase();
		}

		/**
		 * Initialize topping event listeners
		 */
		initToppingListeners() {
			// Listen for topping selection changes
			this.$modal.off('change.modalFooter', '.foodord-product-toppings__input');
			this.$modal.on('change.modalFooter', '.foodord-product-toppings__input', (e) => {
				const $set = $(e.currentTarget).closest('.foodord-product-toppings__set');
				this.clearToppingError($set);
				this.updateAddToCartCta();
			});

			this.$modal.off('change.modalFooter', '.foodord-product-toppings__select');
			this.$modal.on('change.modalFooter', '.foodord-product-toppings__select', (e) => {
				const $set = $(e.currentTarget).closest('.foodord-product-toppings__set');
				this.clearToppingError($set);
				this.updateAddToCartCta();
			});
		}

		initVariationValidation() {
			this.$modal.off('change.modalFooterVariation', '.foodord-attr-input');
			this.$modal.on('change.modalFooterVariation', '.foodord-attr-input', (e) => {
				const $wrapper = $(e.currentTarget).closest('.foodord-attr-wrapper');
				this.clearVariationError($wrapper);
			});

			this.$modal.off('change.modalFooterVariation', '.variations select');
			this.$modal.on('change.modalFooterVariation', '.variations select', (e) => {
				const $wrapper = $(e.currentTarget).closest('.foodord-attr-wrapper');
				this.clearVariationError($wrapper);
			});
		}

		/**
		 * Initialize quantity controls
		 */
		initQuantityControls() {
			const $quantityInput = this.$modal.find('#foodord-quantity-input');
			const $minusBtn = this.$modal.find('#foodord-quantity-minus');
			const $plusBtn = this.$modal.find('#foodord-quantity-plus');

			if (!$quantityInput.length || !$minusBtn.length || !$plusBtn.length) {
				return;
			}

			this.restoreQuantityForCurrentSelection($quantityInput);
			this.schedulePendingQuantityRestore();

			// Minus button handler
			$minusBtn.off('click.modalFooter').on('click.modalFooter', (e) => {
				e.preventDefault();
				const currentValue = parseInt($quantityInput.val(), 10) || 1;
				const minValue = parseInt($quantityInput.attr('min'), 10) || 1;

				if (currentValue > minValue) {
					$quantityInput.val(currentValue - 1).trigger('change');
				}
			});

			// Plus button handler
			$plusBtn.off('click.modalFooter').on('click.modalFooter', (e) => {
				e.preventDefault();
				const currentValue = parseInt($quantityInput.val(), 10) || 1;
				const maxValue = parseInt($quantityInput.attr('max'), 10) || 99;

				if (currentValue < maxValue) {
					$quantityInput.val(currentValue + 1).trigger('change');
				}
			});

			// Input validation
			$quantityInput.off('input.modalFooter change.modalFooter').on('input.modalFooter change.modalFooter', (e) => {
				const $input = $(e.target);
				let value = parseInt($input.val(), 10);
				const minValue = parseInt($input.attr('min'), 10) || 1;
				const maxValue = parseInt($input.attr('max'), 10) || 99;

				// Handle invalid input
				if (isNaN(value) || value < minValue) {
					value = minValue;
				} else if (value > maxValue) {
					value = maxValue;
				}

				$input.val(value);

				// Update button states
				$minusBtn.prop('disabled', value <= minValue);
				$plusBtn.prop('disabled', value >= maxValue);

				// Update CTA dynamic total/count
				this.updateAddToCartCta();
			});

			// Trigger initial validation
			$quantityInput.trigger('change');

		}

		getActiveVariationId() {
			const $form = this.$modal.find('.variations_form');
			if (!$form.length) {
				return 0;
			}

			const raw = parseInt($form.find('input[name="variation_id"]').val(), 10);
			if (Number.isNaN(raw) || raw <= 0) {
				return this._lastFoundVariationId || 0;
			}
			return raw;
		}

		restoreQuantityForCurrentSelection($quantityInputOverride, forcedVariationId = null) {
			if (this._preventAutoRestore) {
				return;
			}

			if (!this.isEditing) {
				this._pendingQuantityRestore = false;
				this._quantityRestoreAttempts = 0;
				return;
			}

			const productId = parseInt(this.$modal.find('.foodord-add-to-cart-btn').data('product-id'), 10) || 0;
			const explicitVariation = typeof forcedVariationId === 'number' ? forcedVariationId : null;
			const variationId = explicitVariation && explicitVariation > 0 ? explicitVariation : this.getActiveVariationId();
			const $input = $quantityInputOverride && $quantityInputOverride.length ? $quantityInputOverride : this.$modal.find('#foodord-quantity-input');
			if (!$input.length) {
				return;
			}

			if (variationId <= 0 && this.hasVariations()) {
				this.queueQuantityRestore();
				return;
			}
			this._pendingQuantityRestore = false;
			this._quantityRestoreAttempts = 0;

			const currentSignature = this.getCurrentToppingsSignature();
			const matchingEntry = FoodOrdModalFooter.findMatchingCartEntry(productId, variationId, currentSignature);
			let targetQuantity = null;

			if (matchingEntry && typeof matchingEntry.quantity === 'number' && matchingEntry.quantity > 0) {
				targetQuantity = matchingEntry.quantity;
			}
			if (targetQuantity === null) {
				const storedQuantity = this.getStoredQuantity(productId, variationId, currentSignature);
				if (storedQuantity && storedQuantity > 0) {
					targetQuantity = storedQuantity;
				}
			}

			if (targetQuantity && targetQuantity > 0) {
				$input.val(targetQuantity).trigger('change');
				if (matchingEntry) {
					const sigToStore = matchingEntry.signature || currentSignature;
					this.persistQuantityPreference(productId, variationId, targetQuantity, sigToStore);
				}
			}
		}

		getQuantityStorageKey(productId, variationId, signature = null) {
			if (!productId) {
				return null;
			}
			const variationSuffix = variationId && variationId > 0 ? '_' + String(variationId) : '';
			if (typeof signature === 'string') {
				const trimmed = signature.trim();
				if (trimmed !== '') {
					return QUANTITY_STORAGE_PREFIX + String(productId) + variationSuffix + '_sig_' + trimmed;
				}
				return QUANTITY_STORAGE_PREFIX + String(productId) + variationSuffix + '_default';
			}
			return QUANTITY_STORAGE_PREFIX + String(productId) + variationSuffix;
		}

		getStoredQuantity(productId, variationId, signature = '') {
			const keysToTry = [];
			const keyWithSignature = this.getQuantityStorageKey(productId, variationId, signature);
			if (keyWithSignature) {
				keysToTry.push(keyWithSignature);
			}
			if (typeof signature === 'string' && signature.trim() !== '') {
				const defaultKey = this.getQuantityStorageKey(productId, variationId, '');
				if (defaultKey) {
					keysToTry.push(defaultKey);
				}
			}
			const legacyKey = this.getQuantityStorageKey(productId, variationId, null);
			if (legacyKey) {
				keysToTry.push(legacyKey);
			}
			const fallbackProductKey = variationId && variationId > 0 ? this.getQuantityStorageKey(productId, 0, null) : null;
			if (fallbackProductKey) {
				keysToTry.push(fallbackProductKey);
			}

			for (let i = 0; i < keysToTry.length; i += 1) {
				const key = keysToTry[i];
				let raw = null;
				try {
					if (typeof window !== 'undefined' && window.localStorage) {
						raw = window.localStorage.getItem(key);
					}
				} catch (_err) {
					void _err;
					raw = null;
				}

				if ((raw === null || typeof raw === 'undefined') && typeof FoodOrdModalFooter.quantityMemory !== 'undefined') {
					raw = FoodOrdModalFooter.quantityMemory[key];
				}

				if (raw === null || typeof raw === 'undefined' || raw === '') {
					raw = this.getCookieValue(key);
				}

				const parsed = parseInt(raw, 10);
				if (Number.isNaN(parsed) || parsed < 1) {
					continue;
				}

				return Math.min(Math.max(parsed, 1), 99);
			}

			return null;
		}

		persistQuantityPreference(productId, variationId, quantity, signature = '') {
			if (!this.isEditing) {
				return;
			}
			const keys = [];
			const keyed = this.getQuantityStorageKey(productId, variationId, signature);
			if (keyed) {
				keys.push(keyed);
			}
			const defaultKey = this.getQuantityStorageKey(productId, variationId, '');
			if (defaultKey) {
				keys.push(defaultKey);
			}
			const legacyKey = this.getQuantityStorageKey(productId, variationId, null);
			if (legacyKey) {
				keys.push(legacyKey);
			}

			if (variationId && variationId > 0) {
				const productLevelKey = this.getQuantityStorageKey(productId, 0, null);
				if (productLevelKey) {
					keys.push(productLevelKey);
				}
			}

			if (!keys.length) {
				return;
			}

			let normalized = parseInt(quantity, 10);
			if (Number.isNaN(normalized)) {
				normalized = 1;
			}
			normalized = Math.min(Math.max(normalized, 1), 99);

			if (typeof FoodOrdModalFooter.quantityMemory === 'undefined') {
				FoodOrdModalFooter.quantityMemory = {};
			}

			keys.forEach((key) => {
				FoodOrdModalFooter.quantityMemory[key] = normalized;
				try {
					if (typeof window !== 'undefined' && window.localStorage) {
						window.localStorage.setItem(key, String(normalized));
					}
				} catch (_err) {
					void _err;
					// Ignore storage errors silently.
				}

				this.setCookieValue(key, String(normalized));
			});
		}

		clearQuantityPreference(productId, variationId, signature = '') {
			const keys = [];
			const keyed = this.getQuantityStorageKey(productId, variationId, signature);
			if (keyed) {
				keys.push(keyed);
			}
			const defaultKey = this.getQuantityStorageKey(productId, variationId, '');
			if (defaultKey) {
				keys.push(defaultKey);
			}
			const legacyKey = this.getQuantityStorageKey(productId, variationId, null);
			if (legacyKey) {
				keys.push(legacyKey);
			}
			if (variationId && variationId > 0) {
				const productLevelKey = this.getQuantityStorageKey(productId, 0, null);
				if (productLevelKey) {
					keys.push(productLevelKey);
				}
			}

			if (!keys.length) {
				return;
			}

			keys.forEach((key) => {
				if (!key) {
					return;
				}
				if (typeof FoodOrdModalFooter.quantityMemory !== 'undefined' && FoodOrdModalFooter.quantityMemory) {
					delete FoodOrdModalFooter.quantityMemory[key];
				}
				try {
					if (typeof window !== 'undefined' && window.localStorage) {
						window.localStorage.removeItem(key);
					}
				} catch (_err) {
					void _err;
					// Ignore storage errors silently.
				}
				if (typeof document !== 'undefined') {
					document.cookie = key + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
				}
			});
		}

		setCookieValue(name, value) {
			if (typeof document === 'undefined') {
				return;
			}
			try {
				const expires = new Date();
				expires.setTime(expires.getTime() + (30 * 24 * 60 * 60 * 1000));
				document.cookie = name + '=' + encodeURIComponent(value) + '; expires=' + expires.toUTCString() + '; path=/';
			} catch (_err) {
				void _err;
				// ignore cookie errors
			}
		}

		getCookieValue(name) {
			if (typeof document === 'undefined' || !name) {
				return null;
			}
			try {
				const cookies = document.cookie ? document.cookie.split(';') : [];
				for (let i = 0; i < cookies.length; i += 1) {
					const cookie = cookies[i].trim();
					if (cookie.indexOf(name + '=') === 0) {
						return decodeURIComponent(cookie.substring(name.length + 1));
					}
				}
			} catch (_err) {
				void _err;
				return null;
			}
			return null;
		}

		/**
		 * Initialize add to cart button in footer
		 */
		initAddToCartButton() {
			const $addToCartBtn = this.$modal.find('.foodord-modal-footer .foodord-add-to-cart-btn');

			if (!$addToCartBtn.length) {
				return;
			}

			$addToCartBtn.off('click.modalFooter').on('click.modalFooter', (e) => {
				e.preventDefault();

				const $button = $(e.currentTarget);
				const productId = $button.data('product-id');
				const quantity = parseInt(this.$modal.find('#foodord-quantity-input').val(), 10) || 1;
				const originalText = $button.html();
				if (!this.validateAddToCartSelections()) {
					return;
				}

				// Disable all footer controls during add to cart
				this.setFooterControlsDisabled(true);
				$button.addClass('is-loading').attr('aria-busy', 'true').html(buildAddToCartLoadingHtml());

				// Check if foodord_modal_vars is available
				if (typeof foodord_modal_vars === 'undefined') {
					console.error('foodord_modal_vars is not defined');
					this.showAddToCartError($button, originalText, 'Configuration error');
					return;
				}

				// Prepare data for custom handler
				const data = {
					action: 'foodord_add_to_cart',
					product_id: productId,
					quantity: quantity,
					nonce: foodord_modal_vars.nonce
				};

				const toppingsSelections = this.collectToppingsSelections();
				if (Object.keys(toppingsSelections).length) {
					data.foodord_toppings = toppingsSelections;
				}

				const currentSignature = this.getCurrentToppingsSignature();
				data.foodord_toppings_signature = currentSignature;

				// Check for variation form and gather variation data
				const $form = this.$modal.find('.variations_form');
				if ($form.length) {
					// Variable product
					const variationId = parseInt($form.find('input[name="variation_id"]').val(), 10) || 0;
					if (!variationId) {
						this.showAddToCartError($button, originalText, 'Please choose product options');
						return;
					}

					data.variation_id = variationId;

					// Add variation attributes
					$form.find('select[name^="attribute_"]').each(function () {
						const $sel = $(this);
						data[$sel.attr('name')] = $sel.val();
					});
				}

				const activeVariationId = data.variation_id ? parseInt(data.variation_id, 10) || 0 : 0;
				const existingEntry = FoodOrdModalFooter.findMatchingCartEntry(parseInt(productId, 10) || 0, activeVariationId, currentSignature);
				if (existingEntry && this.isEditing) {
					data.foodord_base_quantity = existingEntry.quantity;
				}

				const editingKey = this.isEditing && this.editingCartItemKey ? String(this.editingCartItemKey) : '';
				if (editingKey) {
					data.cart_item_key = editingKey;
					data.foodord_editing = '1';
					if (this.originalEditingSignature) {
						data.foodord_original_signature = this.originalEditingSignature;
					}
				}

				const variationIdForStorage = activeVariationId;
				$.post(foodord_modal_vars.ajax_url, data, (response) => {
					if (response.error) {
						let errorMessage = response.error_message || response.error || '';
						if (Array.isArray(response.missing_sets) && response.missing_sets.length) {
							this.markMissingToppingSets(response.missing_sets);
							if (!errorMessage) {
								errorMessage = this.getRequiredSelectionErrorHeading();
							}
						}
						this.showAddToCartError($button, originalText, errorMessage || this.getRequiredSelectionErrorHeading());
					} else {
						if (this.isEditing) {
							this.persistQuantityPreference(productId, variationIdForStorage, quantity, currentSignature);
						}
						this.showAddToCartSuccess($button, originalText);

						// Update cart fragments without triggering added_to_cart event
						if (response.fragments) {
							$.each(response.fragments, function (key, value) {
								$(key).replaceWith(value);
							});
						}

						// Update cart hash
						if (response.cart_hash) {
							$(document.body).trigger('wc_fragment_refresh');
						}

						// Trigger FoodOrd card update
						this.updateFoodordCard();
					}
				}).fail((jqXHR) => {
					console.error('Add to cart network error:', jqXHR);
					this.showAddToCartError($button, originalText, 'Network error occurred');
				});
			});
		}

		validateAddToCartSelections() {
			const variationValidation = this.validateVariationSelections();
			if (!variationValidation.isValid) {
				this.showToast(variationValidation.message || this.getRequiredSelectionErrorHeading(), 'error');
				return false;
			}

			const toppingValidation = this.validateRequiredToppings();
			if (!toppingValidation.isValid) {
				this.showToast(this.getRequiredSelectionErrorHeading(), 'error');
				return false;
			}

			return true;
		}

		collectToppingsSelections() {
			const selections = {};
			const $sets = this.$modal.find('.foodord-product-toppings__set');

			$sets.each(function () {
				const $set = $(this);
				const setId = $set.data('set-id');
				const groupType = $set.data('group-type');
				if (!setId) {
					return;
				}

				if ('dropdown' === groupType) {
					const value = $set.find('select').val();
					if (value) {
						selections[setId] = value;
					}
					return;
				}

				if ('radio' === groupType) {
					const $checked = $set.find('input[type="radio"]:checked');
					if ($checked.length) {
						selections[setId] = $checked.val();
					}
					return;
				}

				const values = [];
				$set.find('input[type="checkbox"]:checked').each(function () {
					const val = $(this).val();
					if (val) {
						values.push(val);
					}
				});
				if (values.length) {
					selections[setId] = values;
				}
			});

			return selections;
		}

		getCurrentToppingsSignature() {
			const selections = this.buildCurrentToppingSelections();
			if (!selections.length) {
				return '';
			}
			return FoodOrdModalFooter.md5(JSON.stringify(selections));
		}

		buildCurrentToppingSelections() {
			const formatted = [];
			const $sets = this.$modal.find('.foodord-product-toppings__set');

			const buildItemData = function ($input) {
				if (!$input || !$input.length) {
					return null;
				}
				const rawLabel = $input.data('option-label') || $input.closest('.foodord-product-toppings__option').find('.foodord-product-toppings__option-label').text();
				const label = $.trim(String(rawLabel || ''));
				if ('' === label) {
					return null;
				}
				const price = parseFloat($input.data('price'));
				return {
					id: String($input.val() || ''),
					label: label,
					price: Number.isNaN(price) ? 0 : price
				};
			};

			$sets.each(function () {
				const $set = $(this);
				const setId = String($set.data('set-id') || '');
				if (!setId) {
					return;
				}
				const groupType = String($set.data('group-type') || 'dropdown');
				const setLabel = String($set.data('set-label') || '');
				const setName = String($set.data('set-name') || '');
				const items = [];

				if ('dropdown' === groupType) {
					const $select = $set.find('select').first();
					if ($select.length) {
						const selectedValue = $select.val();
						if (selectedValue) {
							const $option = $select.find('option').filter(function () {
								return String($(this).val()) === String(selectedValue);
							}).first();
							if ($option.length) {
								const price = parseFloat($option.data('price'));
								const rawLabel = $option.data('option-label') || $option.text();
								const label = $.trim(String(rawLabel || ''));
								if ('' !== label) {
									items.push({
										id: String(selectedValue),
										label: label,
										price: Number.isNaN(price) ? 0 : price
									});
								}
							}
						}
					}
				} else if ('radio' === groupType) {
					const $checked = $set.find('input[type="radio"]:checked');
					if ($checked.length) {
						const itemData = buildItemData($checked);
						if (itemData) {
							items.push(itemData);
						}
					}
				} else {
					$set.find('input[type="checkbox"]:checked').each(function () {
						const itemData = buildItemData($(this));
						if (itemData) {
							items.push(itemData);
						}
					});
				}

				if (items.length) {
					formatted.push({
						set_id: setId,
						set_name: setName,
						set_label: setLabel,
						group_type: groupType,
						items: items
					});
				}
			});

			return formatted;
		}

		clearToppingErrors() {
			const $sets = this.$modal.find('.foodord-product-toppings__set');
			$sets.each((_, element) => {
				this.clearToppingError($(element));
			});
		}

		clearToppingError($set) {
			if (!$set || !$set.length) {
				return;
			}

			$set.removeClass('has-error');
			// Unlike before, we don't remove the error message container
			// as it is no longer used.
			if ($set.attr('tabindex') === '-1') {
				$set.removeAttr('tabindex');
			}
		}

		flagToppingSetError($set, minRequired) {
			if (!$set || !$set.length) {
				return '';
			}

			const message = this.buildToppingErrorMessage($set, minRequired);
			this.clearToppingError($set);
			$set.addClass('has-error');
			// No longer injecting a visible error message element
			return message;
		}

		injectToppingError( /* $set, message */) {
			// no-op: visual inline error UI removed
			return;
		}

		buildToppingErrorMessage($set, minRequired) {
			const titleText = $.trim($set.find('.foodord-product-toppings__set-title').text());
			const labelAttr = $.trim(String($set.data('set-label') || ''));
			const descriptor = titleText || labelAttr || '';

			const humanName = descriptor || '';

			if (minRequired && minRequired > 1) {
				if (humanName) {
					return 'Please select at least ' + minRequired + ' options in "' + humanName + '".';
				}
				return 'Please select at least ' + minRequired + ' options.';
			}

			if (humanName) {
				return 'Please complete the selection for "' + humanName + '".';
			}
			return 'Please complete this selection.';
		}

		getMinRequiredForSet($set) {
			if (!$set || !$set.length) {
				return 0;
			}

			const groupType = String($set.data('group-type') || '');
			const isRequired = String($set.data('is-required') || '') === '1';
			const checkboxMinRaw = parseInt($set.data('checkbox-min'), 10);

			if ('checkbox' === groupType) {
				if (!isNaN(checkboxMinRaw) && checkboxMinRaw > 0) {
					return checkboxMinRaw;
				}
				return isRequired ? 1 : 0;
			}

			return isRequired ? 1 : 0;
		}

		validateRequiredToppings() {
			const result = {
				isValid: true,
				messages: [],
				missingSetIds: []
			};

			const $sets = this.$modal.find('.foodord-product-toppings__set');
			if (!$sets.length) {
				return result;
			}

			this.clearToppingErrors();

			$sets.each((_, element) => {
				const $set = $(element);
				const setId = String($set.data('set-id') || '');
				const groupType = String($set.data('group-type') || '');
				const minRequired = this.getMinRequiredForSet($set);

				if (minRequired <= 0) {
					return;
				}

				let selectionCount = 0;
				if ('checkbox' === groupType) {
					selectionCount = $set.find('input[type="checkbox"]:checked').length;
				} else if ('radio' === groupType) {
					selectionCount = $set.find('input[type="radio"]:checked').length ? 1 : 0;
				} else {
					const value = $.trim(String($set.find('select').val() || ''));
					selectionCount = value ? 1 : 0;
				}

				if (selectionCount < minRequired) {
					const message = this.flagToppingSetError($set, minRequired);
					if (message) {
						result.messages.push(message);
					}
					result.missingSetIds.push(setId);
				}
			});

			if (result.messages.length) {
				result.isValid = false;
				this.focusFirstToppingError();
			}

			return result;
		}

		validateVariationSelections() {
			const result = {
				isValid: true,
				message: ''
			};

			const $forms = this.$modal.find('.variations_form');
			if (!$forms.length) {
				return result;
			}

			this.clearVariationErrors();

			const missingLabels = [];
			$forms.each((_, form) => {
				const $form = $(form);
				$form.find('.foodord-attr-wrapper[data-is-required="1"]').each((__, fieldset) => {
					const $fieldset = $(fieldset);
					const hasRadioSelection = $fieldset.find('.foodord-attr-input:checked').length > 0;
					const hasSelectSelection = $fieldset.find('select').filter(function () {
						return !!$(this).val();
					}).length > 0;

					if (!hasRadioSelection && !hasSelectSelection) {
						this.flagVariationError($fieldset);
						const labelText = $.trim($fieldset.prev('.foodord-attr-legend').find('.foodord-attr-legend-title').text());
						if (labelText) {
							missingLabels.push(labelText);
						}
					}
				});
			});

			if (missingLabels.length) {
				result.isValid = false;
				const uniqueLabels = Array.from(new Set(missingLabels));
				result.message = this.buildVariationErrorMessage(uniqueLabels);
				this.focusFirstVariationError();
			}

			return result;
		}

		clearVariationErrors() {
			const $wrappers = this.$modal.find('.foodord-attr-wrapper.has-variation-error');
			this.$modal.find('.foodord-attr-legend.has-variation-error').removeClass('has-variation-error');
			if (!$wrappers.length) {
				return;
			}

			$wrappers.each((_, element) => {
				this.clearVariationError($(element));
			});
		}

		clearVariationError($wrapper) {
			if (!$wrapper || !$wrapper.length) {
				return;
			}

			$wrapper.removeClass('has-variation-error');
			$wrapper.prev('.foodord-attr-legend').removeClass('has-variation-error');
			if ($wrapper.attr('data-foodord-added-tabindex') === '1') {
				$wrapper.removeAttr('tabindex');
				$wrapper.removeAttr('data-foodord-added-tabindex');
			}
			$wrapper.find('.foodord-attr-input, select').each(function () {
				$(this).removeAttr('aria-invalid');
			});
		}

		flagVariationError($wrapper) {
			if (!$wrapper || !$wrapper.length) {
				return;
			}

			// Restart animation if already present
			$wrapper.removeClass('has-variation-error');
			$wrapper.prev('.foodord-attr-legend').removeClass('has-variation-error');
			void $wrapper[0].offsetWidth; // Force reflow
			$wrapper.addClass('has-variation-error');
			$wrapper.prev('.foodord-attr-legend').addClass('has-variation-error');
			$wrapper.find('.foodord-attr-input, select').attr('aria-invalid', 'true');
			if (typeof $wrapper.attr('tabindex') === 'undefined') {
				$wrapper.attr('tabindex', '-1');
				$wrapper.attr('data-foodord-added-tabindex', '1');
			}
		}

		buildVariationErrorMessage(labels) {
			if (!Array.isArray(labels) || !labels.length) {
				return 'Please choose product options before adding to cart.';
			}

			const safeLabels = labels
				.map((label) => String(label).trim())
				.filter((label) => label.length > 0);

			if (!safeLabels.length) {
				return 'Please choose product options before adding to cart.';
			}

			if (safeLabels.length === 1) {
				return 'Please choose an option for "' + safeLabels[0] + '".';
			}

			return 'Please choose options for: ' + safeLabels.join(', ') + '.';
		}

		focusFirstVariationError() {
			const $firstError = this.$modal.find('.foodord-attr-wrapper.has-variation-error').first();
			if (!$firstError.length) {
				return;
			}

			const $modalBody = this.$modal.find('.foodord-modal-body');
			if (!$modalBody.length) {
				return;
			}

			const $legend = $firstError.prev('.foodord-attr-legend');
			const $scrollTarget = $legend.length ? $legend : $firstError;
			const $titleRow = this.$modal.find('.foodord-product-title-row').first();
			const stickyOffset = Math.max(84, ($titleRow.outerHeight() || 0) + 18);
			const nextScrollTop = Math.max(
				0,
				$scrollTarget.offset().top - $modalBody.offset().top + $modalBody.scrollTop() - stickyOffset
			);

			$modalBody.stop(true).animate({
				scrollTop: nextScrollTop
			}, 300, () => {
				if (typeof $firstError.attr('tabindex') === 'undefined') {
					$firstError.attr('tabindex', '-1');
					$firstError.attr('data-foodord-added-tabindex', '1');
				}
				$firstError.trigger('focus');
			});
		}

		markMissingToppingSets(missingSetIds) {
			if (!Array.isArray(missingSetIds) || !missingSetIds.length) {
				return [];
			}

			const collectedMessages = [];
			this.clearToppingErrors();

			missingSetIds.forEach((setId) => {
				const $set = this.$modal.find('.foodord-product-toppings__set').filter((_, element) => {
					return String($(element).data('set-id') || '') === String(setId);
				}).first();

				if (!$set.length) {
					return;
				}

				const message = this.flagToppingSetError($set, this.getMinRequiredForSet($set));
				if (message) {
					collectedMessages.push(message);
				}
			});

			if (collectedMessages.length) {
				this.focusFirstToppingError();
			}

			return collectedMessages;
		}

		focusFirstToppingError() {
			const $firstError = this.$modal.find('.foodord-product-toppings__set.has-error').first();
			if (!$firstError.length) {
				return;
			}

			const $modalBody = this.$modal.find('.foodord-modal-body');
			if (!$modalBody.length) {
				return;
			}

			const runScroll = () => {
				const $header = $firstError.prev('.foodord-product-toppings__set-header');
				const $scrollTarget = $header.length ? $header : $firstError;
				const modalBodyElement = $modalBody.get(0);
				const targetElement = $scrollTarget.get(0);

				if (!modalBodyElement || !targetElement) {
					return;
				}

				const modalRect = modalBodyElement.getBoundingClientRect();
				const targetRect = targetElement.getBoundingClientRect();
				const $titleRow = this.$modal.find('.foodord-product-title-row').first();
				const stickyOffset = Math.max(84, ($titleRow.outerHeight() || 0) + 18);
				const nextScrollTop = Math.max(
					0,
					modalBodyElement.scrollTop + targetRect.top - modalRect.top - stickyOffset
				);

				$modalBody.stop(true).animate({
					scrollTop: nextScrollTop
				}, 300, () => {
					const firstErrorElement = $firstError.get(0);
					if (!firstErrorElement) {
						return;
					}
					if (typeof $firstError.attr('tabindex') === 'undefined') {
						$firstError.attr('tabindex', '-1');
					}
					if (typeof firstErrorElement.focus === 'function') {
						try {
							firstErrorElement.focus({ preventScroll: true });
						} catch (_err) {
							void _err;
							firstErrorElement.focus();
						}
					}
					if (typeof window.requestAnimationFrame === 'function') {
						window.requestAnimationFrame(() => {
							modalBodyElement.scrollTop = nextScrollTop;
						});
					}
				});
			};

			if (typeof window.requestAnimationFrame === 'function') {
				window.requestAnimationFrame(runScroll);
			} else {
				runScroll();
			}
		}

		/**
		 * Show add to cart success state
		 * @param {jQuery} $button - Button element
		 * @param {string} originalText - Original button text
		 */
		showAddToCartSuccess(_button, _originalText) {
			// mark params as used to satisfy eslint
			void _button; void _originalText;
			const wasEditing = this.isEditing;
			const productId = parseInt(this.$modal.find('.foodord-add-to-cart-btn').data('product-id'), 10) || 0;
			const variationId = this.getActiveVariationId();
			const currentSignature = this.getCurrentToppingsSignature();
			if (!wasEditing && productId) {
				this.clearQuantityPreference(productId, variationId, currentSignature);
			}
			this.clearEditingState();
			// Close modal immediately after successful add to cart
			if (this.modal && typeof this.modal.closeModal === 'function') {
				this.modal.closeModal();
			}
		}
		/**
		 * Show add to cart error state
		 * @param {jQuery} $button - Button element
		 * @param {string} originalText - Original button text
		 * @param {string} errorMessage - Error message
		 */
		showAddToCartError($button, originalText, errorMessage) {
			console.error('Add to cart error:', errorMessage);
			if (errorMessage) {
				this.showToast(String(errorMessage), 'error');
			} else {
				this.showToast(this.getRequiredSelectionErrorHeading(), 'error');
			}
			$button.removeClass('is-loading').removeAttr('aria-busy').html(originalText);
			this.setFooterControlsDisabled(false);
		}

		getRequiredSelectionErrorHeading() {
			const label = getI18nString('requiredSelectionsBeforeAddToCart');
			return label || 'Please complete the required selections before adding to cart.';
		}

		/**
		 * Enable/disable footer controls
		 * @param {boolean} disabled - Whether to disable controls
		 */
		setFooterControlsDisabled(disabled) {
			const $footer = this.$modal.find('.foodord-modal-footer');
			const $button = $footer.find('.foodord-add-to-cart-btn');

			$footer.find('button, input').prop('disabled', disabled);

			if (disabled) {
				$footer.addClass('loading');
				$button.addClass('is-loading').attr('aria-busy', 'true');
			} else {
				$footer.removeClass('loading');
				$button.removeClass('is-loading').removeAttr('aria-busy');
			}
		}

		/**
		 * Update FoodOrd card after successful add to cart
		 */
		updateFoodordCard() {
			// Update cart data via AJAX for ADD TO CART only
			if (typeof foodord_modal_vars !== 'undefined') {
				if (typeof window.FoodordCard !== 'undefined' && typeof window.FoodordCard.showUpsellSkeleton === 'function') {
					window.FoodordCard.showUpsellSkeleton(true);
				}

				if (typeof window.FoodordMobileCart !== 'undefined' && typeof window.FoodordMobileCart.showUpsellSkeleton === 'function') {
					window.FoodordMobileCart.showUpsellSkeleton(true);
				}

				$.post(foodord_modal_vars.ajax_url, {
					action: 'foodord_get_cart_items',
					nonce: foodord_modal_vars.nonce
				}, (response) => {
					if (response.success && response.data) {
						if (typeof window.FoodordCard !== 'undefined' && typeof window.FoodordCard.applyCartResponse === 'function') {
							window.FoodordCard.applyCartResponse(response.data);
						} else {
							if (Object.prototype.hasOwnProperty.call(response.data, 'show_topping_group_labels')) {
								setShowToppingGroupLabels(response.data.show_topping_group_labels);
							}
							this.renderCartItems(response.data.cart_items, response.data.cart_total_html, response.data);

							// Update clear button state
							setTimeout(() => {
								if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateClearButton) {
									window.FoodordCard.updateClearButton();
								}
							}, 100);

							// Update CTA state with delivery fee
							if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateCTAState) {
								window.FoodordCard.updateCTAState(response.data);
							}
						}

						// Trigger foodord_cart_updated event for mobile cart and other listeners
						document.dispatchEvent(new CustomEvent('foodord_cart_updated', {
							detail: response.data
						}));
					}
				}).fail(() => {
					// Fallback: just update clear button
					if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateClearButton) {
						window.FoodordCard.updateClearButton();
					}
				});
			} else {
				// Just update clear button state
				if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateClearButton) {
					window.FoodordCard.updateClearButton();
				}
			}
		}

		/**
		 * Render cart items in FoodOrd card
		 */
		renderCartItems(cartItems, cartTotalHtml, metadata = null) {
			if (metadata && Object.prototype.hasOwnProperty.call(metadata, 'show_topping_group_labels')) {
				setShowToppingGroupLabels(metadata.show_topping_group_labels);
			}

			if (Array.isArray(cartItems)) {
				FoodOrdModalFooter.setCartSnapshot(cartItems);
			} else {
				FoodOrdModalFooter.setCartSnapshot([]);
			}

			const $card = $('.foodord-sidebar .wr-card, .wr-card');
			if (!$card.length) {
				return;
			}

			const $body = $card.find('.wr-card__body');
			const $footer = $card.find('.wr-card__cta');
			const emptyIconHtml = '<svg class="wr-card__empty-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"></path><line x1="3" y1="6" x2="21" y2="6"></line><path d="M16 10a4 4 0 0 1-8 0"></path></svg>';

			if (cartItems.length === 0) {
				// Show empty cart state
				const emptyText = escapeHtml(getI18nString('emptyCartText'));
				const emptySubtext = escapeHtml(getI18nString('emptyCartSubtext'));
				const emptyMarkup =
					'<div class="wr-card__empty">' +
					emptyIconHtml +
					(emptyText ? '<p class="wr-card__empty-text">' + emptyText + '</p>' : '') +
					(emptySubtext ? '<p class="wr-card__empty-subtext">' + emptySubtext + '</p>' : '') +
					'</div>';
				$body.html(emptyMarkup);

				const zeroTotal = (typeof foodord_modal_vars.cart_zero_html !== 'undefined') ? foodord_modal_vars.cart_zero_html : '0';
				$footer.html(buildCtaHtml(0, zeroTotal));
				$footer.addClass('disabled').prop('disabled', true).attr('aria-disabled', 'true');
			} else {
				// Show cart items
				const $items = $('<div class="wr-card__items"></div>');
				const escapeForAttr = function (value) {
					return $('<div></div>').text(value).html();
				};
				const escapeForText = function (value) {
					return $('<div></div>').text(value).html();
				};

				FoodOrdModalFooter.setCartSnapshot(Array.isArray(cartItems) ? cartItems : []);

				$.each(cartItems, function (_, item) {
					const quantity = item.quantity || 1;
					const productIdAttr = (typeof item.product_id !== 'undefined' && item.product_id) ? item.product_id : item.id;
					const rawVariationId = typeof item.variation_id !== 'undefined' ? parseInt(item.variation_id, 10) : 0;
					const variationIdAttr = isNaN(rawVariationId) ? 0 : rawVariationId;

					// Render toppings HTML
					let toppingsHtml = '';
					if (Array.isArray(item.toppings) && item.toppings.length > 0) {
						const setsHtml = item.toppings
							.map(function (set) {
								if (!set || !Array.isArray(set.items) || set.items.length === 0) {
									return '';
								}

								const titleSource = (typeof set.set_label === 'string' && set.set_label !== '')
									? set.set_label
									: (typeof set.set_name === 'string' && set.set_name !== '' ? set.set_name : 'Toppings');
								const title = $('<div>').text(titleSource).html();

								const itemsHtml = set.items
									.map(function (toppingItem) {
										if (typeof toppingItem !== 'string' || toppingItem === '') {
											return '';
										}
										return '<span class="wr-card__item-topping">' + $('<div>').text(toppingItem).html() + '</span>';
									})
									.filter(Boolean)
									.join('');

								if (itemsHtml === '') {
									return '';
								}

								const titleBlock = showToppingGroupLabels ? '<div class="wr-card__item-topping-title">' + title + '</div>' : '';

								return '<div class="wr-card__item-topping-set">' + titleBlock + '<div class="wr-card__item-topping-list">' + itemsHtml + '</div></div>';
							})
							.filter(Boolean)
							.join('');

						if (setsHtml) {
							toppingsHtml = '<div class="wr-card__item-toppings">' + setsHtml + '</div>';
						}
					}

					const noteMarkup = (window.FoodordCartNotes && typeof window.FoodordCartNotes.renderNoteMarkup === 'function')
						? window.FoodordCartNotes.renderNoteMarkup(item, 'desktop', { includeToggle: false })
						: '';
					const noteToggleMarkup = (window.FoodordCartNotes && typeof window.FoodordCartNotes.renderNoteToggleMarkup === 'function')
						? window.FoodordCartNotes.renderNoteToggleMarkup(item, 'desktop')
						: '';
					const cartItemKeyAttr = item && item.cart_item_key ? escapeForAttr(String(item.cart_item_key)) : '';
					const noteAttr = item && typeof item.note === 'string' ? escapeForAttr(item.note) : '';
					const signatureAttr = item && typeof item.toppings_signature === 'string' ? escapeForAttr(item.toppings_signature) : '';

					const rawName = typeof item.name === 'string' ? item.name : '';
					const escapedName = escapeForText(rawName);
					const ariaLabel = escapeForAttr(buildEditLabel(rawName));
					$items.append(
						'<div class="wr-card__item" data-product-id="' + productIdAttr + '" data-variation-id="' + variationIdAttr + '" data-quantity="' + quantity + '" data-cart-item-key="' + cartItemKeyAttr + '" data-note="' + noteAttr + '" data-toppings-signature="' + signatureAttr + '">' +
						'<div class="wr-card__item-details">' +
						'<h4 class="wr-card__item-title">' +
						'<button type="button" class="wr-card__item-title-button" aria-label="' + ariaLabel + '">' + escapedName + '</button>' +
						'</h4>' +
						toppingsHtml +
						noteToggleMarkup +
						'</div>' +
						'<div class="wr-card__item-actions">' +
						'<div class="wr-card__item-price">' + item.price + '</div>' +
						'<div class="wr-card__item-quantity" data-quantity="' + quantity + '">' +
						'<div class="wr-card__quantity-popover active">' +
						'<button class="wr-card__quantity-btn ' + (quantity === 1 ? 'minus trash' : 'minus') + '" data-action="minus">' + (quantity === 1 ? '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>' : '') + '</button>' +
						'<span class="wr-card__quantity-value">' + quantity + '</span>' +
						'<button class="wr-card__quantity-btn plus" data-action="plus"></button>' +
						'</div>' +
						'</div>' +
						'</div>' +
						noteMarkup +
						'</div>'
					);
				});

				$body.html($items);
				// Update footer button with left label and right total
				const totalHtml = cartTotalHtml || '';
				const cartCount = Array.isArray(cartItems)
					? cartItems.reduce(function (count, cartItem) {
						const quantity = parseInt(cartItem.quantity || 1, 10);
						return count + (isNaN(quantity) ? 0 : quantity);
					}, 0)
					: 0;
				$footer.html(buildCtaHtml(cartCount, totalHtml));
				$footer
					.removeClass('disabled')
					.prop('disabled', false)
					.removeAttr('aria-disabled')
					.removeAttr('style');
			}

			// Update clear button state after render
			setTimeout(function () {
				if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateClearButton) {
					window.FoodordCard.updateClearButton();
				}
				if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateCartCount) {
					window.FoodordCard.updateCartCount();
				}
			}, 50);
		}

		/**
		 * Reset footer state when modal closes
		 */
		resetFooterState() {
			this.clearEditingState();
			this.clearAllToppingSelections(false);
			const $quantityInput = this.$modal.find('#foodord-quantity-input');

			// Reset quantity to 1
			if ($quantityInput.length) {
				$quantityInput.val(1).trigger('change');
			}

			// Re-enable all controls
			this.setFooterControlsDisabled(false);

			// Ensure CTA reflects reset state
			this.clearToppingErrors();
			this.clearVariationErrors();
			this.updateAddToCartCta();
		}

		/**
		 * Update modal CTA (quantity and total price) similar to card CTA
		 */
		updateAddToCartCta() {
			const $btn = this.$modal.find('.foodord-modal-footer .foodord-add-to-cart-btn');
			if (!$btn.length) return;
			if ($btn.hasClass('is-loading')) return;

			const qty = parseInt(this.$modal.find('#foodord-quantity-input').val(), 10) || 1;
			const $countEl = $btn.find('.foodord-add-to-cart-count');
			const $totalEl = $btn.find('.foodord-add-to-cart-total');

			// Get base unit price (may be updated by variations)
			const unitPrice = parseFloat($btn.data('unit-price'));
			const originalUnitPrice = parseFloat($btn.data('unit-price-original'));
			const basePrice = !isNaN(originalUnitPrice) ? originalUnitPrice : (!isNaN(unitPrice) ? unitPrice : 0);

			// Calculate toppings price
			const toppingsPrice = this.calculateToppingsPrice();

			// Calculate final price including toppings
			const finalUnitPrice = basePrice + toppingsPrice;
			const total = finalUnitPrice * qty;

			// Update quantity display
			if ($countEl.length) {
				$countEl.text(String(qty));
			}

			// Update total price display
			if ($totalEl.length) {
				if (!isNaN(finalUnitPrice)) {
					$totalEl.html(this.formatCurrency(total));
				} else if (typeof foodord_modal_vars !== 'undefined' && foodord_modal_vars.cart_zero_html) {
					$totalEl.html(foodord_modal_vars.cart_zero_html);
				}
			}

			// Store toppings extra for other scripts
			$btn.data('toppings-extra', toppingsPrice);
		}


		/**
		 * Calculate toppings price from current selections
		 * @returns {number}
		 */
		calculateToppingsPrice() {
			let totalToppingsPrice = 0;

			// Calculate radio/checkbox selections using data-price attributes when available
			this.$modal.find('.foodord-product-toppings__input:checked').each(function () {
				const $input = $(this);
				const attrPrice = parseFloat($input.data('price'));
				if (!isNaN(attrPrice)) {
					totalToppingsPrice += attrPrice;
					return;
				}
				// Fallback to parsing visible price text if attribute is missing
				const $priceSpan = $input.closest('.foodord-product-toppings__option')
					.find('.foodord-product-toppings__option-price');
				if ($priceSpan.length) {
					const priceText = $priceSpan.text().replace(/[^\d.,]/g, '');
					const price = parseFloat(priceText.replace(',', '.')) || 0;
					totalToppingsPrice += price;
				}
			});

			// Calculate select selections (prefer data-price attribute on option)
			this.$modal.find('.foodord-product-toppings__select').each(function () {
				const $select = $(this);
				const $selectedOption = $select.find('option:selected');
				const attrPrice = parseFloat($selectedOption.data('price'));
				if (!isNaN(attrPrice)) {
					totalToppingsPrice += attrPrice;
					return;
				}
				// Fallback: extract from text "Label (€5.00)"
				const optionText = $selectedOption.text();
				const priceMatch = optionText.match(/\(([^)]+)\)$/);
				if (priceMatch) {
					const priceText = priceMatch[1].replace(/[^\d.,]/g, '');
					const price = parseFloat(priceText.replace(',', '.')) || 0;
					totalToppingsPrice += price;
				}
			});

			return totalToppingsPrice;
		}

		/**
		 * Format currency with WooCommerce settings
		 * @param {number} amount
		 * @returns {string}
		 */
		formatCurrency(amount) {
			const cfg = (typeof foodord_modal_vars !== 'undefined') ? foodord_modal_vars : {};
			const symbol = cfg.currency_symbol || '';
			const pos = cfg.currency_pos || 'left';
			const decimals = (typeof cfg.price_decimals === 'number') ? cfg.price_decimals : 2;
			const decSep = cfg.price_decimal_sep || '.';
			const thouSep = cfg.price_thousand_sep || ',';

			const negative = amount < 0;
			const n = Math.abs(amount);
			const fixed = n.toFixed(decimals);
			const [intPartRaw, decPart] = fixed.split('.');
			let intPart = intPartRaw;
			intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, thouSep);
			let number = intPart;
			if (decimals > 0) {
				number += decSep + (decPart || '').padEnd(decimals, '0');
			}
			let out = '';
			switch (pos) {
				case 'left':
					out = symbol + number; break;
				case 'right':
					out = number + symbol; break;
				case 'left_space':
					out = symbol + ' ' + number; break;
				case 'right_space':
					out = number + ' ' + symbol; break;
				default:
					out = symbol + number; break;
			}
			return negative ? '-' + out : out;
		}

		/**
		 * Show toast message inside modal context without affecting layout
		 * @param {string} message
		 * @param {'error'|'success'|'info'} type
		 */
		showToast(message, type = 'error') {
			try {
				// Use the modal as the container for the toast
				const $modalContent = this.$modal.find('.foodord-modal-content');
				if (!$modalContent.length) {
					return;
				}

				let $container = $modalContent.find('.foodord-toast-container');
				if (!$container.length) {
					$container = jQuery('<div class="foodord-toast-container" aria-live="assertive" aria-atomic="true"></div>');
					$modalContent.append($container);
				}

				let safeMessage = String(message || '');
				if (safeMessage.split(' ').length > 15) {
					safeMessage = safeMessage.split(' ').slice(0, 15).join(' ') + '...';
				}
				const toastClass = 'foodord-toast foodord-toast--' + String(type || 'error');
				const $toast = jQuery('<div class="' + toastClass + '" role="alert"></div>').text(safeMessage);

				$container.append($toast);

				// Auto remove after 3 seconds with fade-out
				setTimeout(function () {
					$toast.addClass('is-hiding');
					setTimeout(function () {
						$toast.remove();
						if (!$container.children().length) {
							$container.remove();
						}
					}, 300);
				}, 3000);
			} catch (e) {
				// Fallback to console
				console.error('Toast error:', message, e);
			}
		}
	}

	// Expose to global scope for modal integration
	window.FoodOrdModalFooter = FoodOrdModalFooter;
	FoodOrdModalFooter._listenersReady = false;
	FoodOrdModalFooter.cartSnapshot = [];
	if (typeof FoodOrdModalFooter.quantityMemory === 'undefined') {
		FoodOrdModalFooter.quantityMemory = {};
	}

	// Basit cart render - gerçek WooCommerce sepetini kullan
	jQuery(document).ready(function ($) {
		if (typeof foodord_modal_vars === 'undefined' || !Array.isArray(foodord_modal_vars.cart_items)) {
			if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateClearButton) {
				window.FoodordCard.updateClearButton();
			}
			return;
		}

		const cartItems = foodord_modal_vars.cart_items;
		const showLabels = (typeof window.FoodordShowToppingGroupLabels !== 'undefined') ? !!window.FoodordShowToppingGroupLabels : true;

		if (!cartItems.length) {
			if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateClearButton) {
				window.FoodordCard.updateClearButton();
			}
			return;
		}

		const $card = $('.foodord-sidebar .wr-card, .wr-card');
		if (!$card.length) {
			return;
		}

		const $body = $card.find('.wr-card__body');
		const $footer = $card.find('.wr-card__cta');
		$body.empty();

		const $items = $('<div class="wr-card__items"></div>');
		const escapeForAttr = function (value) {
			return $('<div></div>').text(value).html();
		};

		$.each(cartItems, function (_, item) {
			const quantity = item.quantity || 1;
			const productIdAttr = (typeof item.product_id !== 'undefined' && item.product_id) ? item.product_id : item.id;
			const rawVariationId = typeof item.variation_id !== 'undefined' ? parseInt(item.variation_id, 10) : 0;
			const variationIdAttr = isNaN(rawVariationId) ? 0 : rawVariationId;
			let toppingsHtml = '';

			if (Array.isArray(item.toppings) && item.toppings.length > 0) {
				const setsHtml = item.toppings
					.map(function (set) {
						if (!set || !Array.isArray(set.items) || set.items.length === 0) {
							return '';
						}

						const titleSource = (typeof set.set_label === 'string' && set.set_label !== '')
							? set.set_label
							: (typeof set.set_name === 'string' && set.set_name !== '' ? set.set_name : 'Toppings');
						const title = $('<div>').text(titleSource).html();

						const itemsHtml = set.items
							.map(function (toppingItem) {
								if (typeof toppingItem !== 'string' || toppingItem === '') {
									return '';
								}
								return '<span class="wr-card__item-topping">' + $('<div>').text(toppingItem).html() + '</span>';
							})
							.filter(Boolean)
							.join('');

						if (itemsHtml === '') {
							return '';
						}

						const titleBlock = showLabels ? '<div class="wr-card__item-topping-title">' + title + '</div>' : '';
						return '<div class="wr-card__item-topping-set">' + titleBlock + '<div class="wr-card__item-topping-list">' + itemsHtml + '</div></div>';
					})
					.filter(Boolean)
					.join('');

				if (setsHtml) {
					toppingsHtml = '<div class="wr-card__item-toppings">' + setsHtml + '</div>';
				}
			}

			const noteMarkup = (window.FoodordCartNotes && typeof window.FoodordCartNotes.renderNoteMarkup === 'function')
				? window.FoodordCartNotes.renderNoteMarkup(item, 'desktop', { includeToggle: false })
				: '';
			const noteToggleMarkup = (window.FoodordCartNotes && typeof window.FoodordCartNotes.renderNoteToggleMarkup === 'function')
				? window.FoodordCartNotes.renderNoteToggleMarkup(item, 'desktop')
				: '';
			const cartItemKeyAttr = item && item.cart_item_key ? escapeForAttr(String(item.cart_item_key)) : '';
			const noteAttr = item && typeof item.note === 'string' ? escapeForAttr(item.note) : '';
			const signatureAttr = item && typeof item.toppings_signature === 'string' ? escapeForAttr(item.toppings_signature) : '';

			$items.append(
				'<div class="wr-card__item" data-product-id="' + productIdAttr + '" data-variation-id="' + variationIdAttr + '" data-quantity="' + quantity + '" data-cart-item-key="' + cartItemKeyAttr + '" data-note="' + noteAttr + '" data-toppings-signature="' + signatureAttr + '">' +
				'<div class="wr-card__item-details">' +
				'<h4 class="wr-card__item-title">' + item.name + '</h4>' +
				toppingsHtml +
				noteToggleMarkup +
				'</div>' +
				'<div class="wr-card__item-actions">' +
				'<div class="wr-card__item-price">' + item.price + '</div>' +
				'<div class="wr-card__item-quantity" data-quantity="' + quantity + '">' +
				'<div class="wr-card__quantity-popover active">' +
				'<button class="wr-card__quantity-btn ' + (quantity === 1 ? 'minus trash' : 'minus') + '" data-action="minus">' + (quantity === 1 ? '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>' : '') + '</button>' +
				'<span class="wr-card__quantity-value">' + quantity + '</span>' +
				'<button class="wr-card__quantity-btn plus" data-action="plus"></button>' +
				'</div>' +
				'</div>' +
				'</div>' +
				noteMarkup +
				'</div>'
			);
		});

		$body.append($items);

		const totalInit = (typeof foodord_modal_vars.cart_total_html !== 'undefined') ? foodord_modal_vars.cart_total_html : '';
		const initialCount = cartItems.reduce(function (count, cartItem) {
			const qty = parseInt(cartItem.quantity || 1, 10);
			return count + (isNaN(qty) ? 0 : qty);
		}, 0);

		$footer
			.html(buildCtaHtml(initialCount, totalInit))
			.removeClass('disabled')
			.prop('disabled', false)
			.removeAttr('aria-disabled')
			.removeAttr('style');

		setTimeout(function () {
			if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateClearButton) {
				window.FoodordCard.updateClearButton();
			}
		}, 100);

		if (typeof window.FoodordCard !== 'undefined' && window.FoodordCard.updateClearButton) {
			window.FoodordCard.updateClearButton();
		}
	});

})(jQuery);
