(function ($) {
    class PPCPManager {
        constructor(ppcp_manager) {
            // 9.0.66
            this.ppcp_manager = ppcp_manager;
            this.productAddToCart = true;
            this.lastApiResponse = null;
            this.ppcp_address = [];
            this.paymentsClient = null;
            this.allowedPaymentMethods = [];
            this.merchantInfo = null;
            this.pageContext = 'unknown';
            this.ppcp_used_payment_method = null;
            this.googleSelectedShippingId = '';
            this.googleShippingIdMap = {};
            this.appleSelectedShippingId = '';
            this.appleShippingIdMap = {};
            this.init();
            this.ppcp_cart_css();
        }

        init() {
            if (typeof this.ppcp_manager === 'undefined') {
                console.log("PPCP Manager configuration is undefined.");
                return false;
            }
            const lastError = (ppcp_manager?.last_error || '').trim();
            if (lastError) {
                console.log(lastError);
                $(document.body).trigger('ppcp_checkout_error', lastError);
            }
            this.debouncedTogglePlaceOrderButton = this.debounce_place_order(this.togglePlaceOrderButton.bind(this), 4);
            this.manageVariations('#ppcp_product, .google-pay-container, .apple-pay-container');
            this.bindCheckoutEvents();
            if (this.ppcp_manager.advanced_card_payments === 'yes') {
                this.debouncedUpdatePaypalCC = this.debounce_cc(this.syncPayPalCardFields.bind(this), 500);
            }
            this.debouncedUpdatePaypalCheckout = this.debounce(this.syncPayPalCheckoutButtons.bind(this), 500);
            if (this.ppcp_manager.enabled_google_pay === 'yes') {
                this.debouncedUpdateGooglePay = this.debounce_google(this.syncGooglePayButton.bind(this), 500);
            }
            if (this.ppcp_manager.enabled_apple_pay === 'yes') {
                this.debouncedUpdateApplePay = this.debounce_apple(this.syncApplePayButton.bind(this), 500);
            }
            if (this.isCheckoutPage() === false) {
                this.debouncedUpdatePaypalCheckout();
                if (this.ppcp_manager.enabled_google_pay === 'yes') {
                    this.debouncedUpdateGooglePay();
                }
                if (this.ppcp_manager.enabled_apple_pay === 'yes') {
                    this.debouncedUpdateApplePay();
                }
            } else {
                this.debouncedUpdatePaypalCheckout();
                if (this.ppcp_manager.enabled_google_pay === 'yes') {
                    this.debouncedUpdateGooglePay();
                }
                if (this.ppcp_manager.enabled_apple_pay === 'yes') {
                    this.debouncedUpdateApplePay();
                }
                if (this.ppcp_manager.advanced_card_payments === 'yes') {
                    this.debouncedUpdatePaypalCC();
                }
            }
            setTimeout(function () {
                $('#wfacp_smart_buttons.wfacp-dynamic-checkout-loading .dynamic-checkout__skeleton').hide();
            }, 1000);
        }
        
        t(key, fallback = '') {
            const raw = this.ppcp_manager ? this.ppcp_manager[key] : undefined;
            if (raw === null || raw === undefined || raw === '') {
                return fallback;
            }
            const v = String(raw);
            return (v && v !== 'undefined' && v !== 'null') ? v : fallback;
        }

        getAddress(prefix) {
            const fields = {
                addressLine1: jQuery(`#${prefix}_address_1`).val(),
                addressLine2: jQuery(`#${prefix}_address_2`).val(),
                adminArea1: jQuery(`#${prefix}_state`).val(),
                adminArea2: jQuery(`#${prefix}_city`).val(),
                postalCode: jQuery(`#${prefix}_postcode`).val(),
                countryCode: jQuery(`#${prefix}_country`).val(),
                firstName: jQuery(`#${prefix}_first_name`).val(),
                lastName: jQuery(`#${prefix}_last_name`).val(),
                email: jQuery(`#${prefix}_email`).val()
            };

            fields.phoneNumber = prefix === 'billing' ?
                    jQuery('#billing-phone').val() || jQuery('#shipping-phone').val() :
                    jQuery('#shipping-phone').val() || jQuery('#billing-phone').val();

            let customerData = {};
            let addressData = {};

            if (!fields.addressLine1) {
                if (typeof wp !== 'undefined' && wp.data?.select) {
                    try {
                        customerData = wp.data.select('wc/store/cart').getCustomerData();
                    } catch (e) {
                        console.warn('Could not fetch customerData:', e);
                    }
                }
                const {billingAddress, shippingAddress} = customerData;
                addressData = (prefix === 'billing') ? billingAddress : shippingAddress;

                Object.assign(fields, {
                    addressLine1: addressData.address_1,
                    addressLine2: addressData.address_2,
                    adminArea1: addressData.state,
                    adminArea2: addressData.city,
                    postalCode: addressData.postcode,
                    countryCode: addressData.country,
                    firstName: addressData.first_name,
                    lastName: addressData.last_name,
                    email: prefix === 'billing' ? billingAddress.email || shippingAddress.email : shippingAddress.email || billingAddress.email
                });
            }

            // Start with the standard fields
            const result = {
                [`${prefix}_address_1`]: fields.addressLine1 || '',
                [`${prefix}_address_2`]: fields.addressLine2 || '',
                [`${prefix}_state`]: fields.adminArea1 || '',
                [`${prefix}_city`]: fields.adminArea2 || '',
                [`${prefix}_postcode`]: fields.postalCode || '',
                [`${prefix}_country`]: fields.countryCode || '',
                [`${prefix}_first_name`]: fields.firstName || '',
                [`${prefix}_last_name`]: fields.lastName || '',
                [`${prefix}_email`]: fields.email || '',
                [`${prefix}_phone`]: fields.phoneNumber || ''
            };

            // Add ALL other fields from addressData (including custom fields)
            if (addressData && Object.keys(addressData).length > 0) {
                Object.keys(addressData).forEach(key => {
                    const fieldKey = `${prefix}_${key}`;
                    // Only add if it's not already in our standard fields
                    if (!result.hasOwnProperty(fieldKey)) {
                        result[fieldKey] = addressData[key] !== undefined && addressData[key] !== null
                                ? addressData[key]
                                : '';
                    }
                });
            }

            return result;
        }

        getValidAddress(prefix) {
            const address = this.getAddress(prefix);
            return this.isValidAddress(prefix, address) ? address : this.getAddress(prefix === 'billing' ? 'shipping' : 'billing');
        }

        getBillingAddress() {
            return this.getValidAddress('billing');
        }

        getShippingAddress() {
            return this.getValidAddress('shipping');
        }

        isValidAddress(prefix, address) {
            return address && address[`${prefix}_address_1`];
        }

        // Convert a Google Pay / Apple Pay wallet address to WooCommerce form-field format.
        // Used as a fallback when the Block Checkout form has not been filled in
        // before the customer clicks the express wallet button. Apple Pay populates
        // both `name` (given) and `surname` (family); Google Pay puts the full name
        // in `name` only.
        walletToWCFormat(walletAddr, prefix) {
            if (!walletAddr) {
                return {};
            }
            const rawName = (walletAddr.name || '').trim();
            const rawSurname = (walletAddr.surname || '').trim();
            let firstName = '';
            let lastName = '';
            if (rawName && rawSurname) {
                firstName = rawName;
                lastName = rawSurname;
            } else if (rawName) {
                const parts = rawName.split(/\s+/);
                firstName = parts.shift() || '';
                lastName = parts.join(' ');
            } else if (rawSurname) {
                lastName = rawSurname;
            }
            const result = {
                [`${prefix}_first_name`]: firstName,
                [`${prefix}_last_name`]: lastName,
                [`${prefix}_address_1`]: walletAddr.address1 || '',
                [`${prefix}_address_2`]: walletAddr.address2 || '',
                [`${prefix}_city`]: walletAddr.city || '',
                [`${prefix}_state`]: walletAddr.state || '',
                [`${prefix}_postcode`]: walletAddr.postcode || '',
                [`${prefix}_country`]: walletAddr.country || '',
                [`${prefix}_phone`]: walletAddr.phoneNumber || ''
            };
            if (prefix === 'billing' && walletAddr.emailAddress) {
                result.billing_email = walletAddr.emailAddress;
            }
            return result;
        }

        isCheckoutPage() {
            return this.ppcp_manager.page === 'checkout';
        }

        isProductPage() {
            return this.ppcp_manager.page === 'product';
        }

        isCartPage() {
            return this.ppcp_manager.page === 'cart';
        }

        isSale() {
            return this.ppcp_manager.paymentaction === 'capture';
        }

        throttle(func, limit) {
            let lastCall = 0;
            return function (...args) {
                const now = Date.now();
                if (now - lastCall >= limit) {
                    lastCall = now;
                    func.apply(this, args);
                }
            };
        }

        debounce(func, delay) {
            let timer;
            return function (...args) {
                clearTimeout(timer);
                timer = setTimeout(() => func.apply(this, args), delay);
            };
        }

        debounce_google(func, delay) {
            let timer;
            return function (...args) {
                clearTimeout(timer);
                timer = setTimeout(() => func.apply(this, args), delay);
            };
        }

        debounce_apple(func, delay) {
            let timer;
            return function (...args) {
                clearTimeout(timer);
                timer = setTimeout(() => func.apply(this, args), delay);
            };
        }

        debounce_place_order(func, delay) {
            let timer;
            return function (...args) {
                clearTimeout(timer);
                timer = setTimeout(() => func.apply(this, args), delay);
            };
        }

        debounce_cc(func, delay) {
            let timer;
            return function (...args) {
                clearTimeout(timer);
                timer = setTimeout(() => func.apply(this, args), delay);
            };
        }

        bindCheckoutEvents() {
            $('form.checkout').on('click', 'input[name="payment_method"]', () => {
                this.debouncedTogglePlaceOrderButton();
                $(document.body).trigger('wpg_change_method');
            });
            $('#order_review').on('click', 'input[name="payment_method"]', () => {
                this.debouncedTogglePlaceOrderButton();
                $(document.body).trigger('wpg_change_method');
            });
            if (this.ppcp_manager.is_pay_page === 'yes') {
                this.debouncedTogglePlaceOrderButton();
            }
            $(document.body).on('ppcp_cc_checkout_updated ppcp_checkout_updated ppcp_cc_block_ready ppcp_block_ready', () => {
                this.debouncedTogglePlaceOrderButton();
            });
            $('form.checkout').on('checkout_place_order_wpg_paypal_checkout_cc', (event) => {
                event.preventDefault();
                return this.handleCheckoutSubmit(event);
            });

            $('#order_review').on('submit', (event) => {
                if (this.isPpcpCCSelected()) {
                    event.preventDefault();
                    return this.handleCheckoutSubmit();
                }
            });

            const eventSelectors = 'added_to_cart updated_cart_totals wc_fragments_refreshed wc_fragment_refresh wc_fragments_loaded updated_checkout ppcp_block_ready ppcp_checkout_updated wc_update_cart wc_cart_emptied wpg_change_method fkwcs_express_button_init';
            const checkoutSelectors = 'updated_cart_totals wc_fragments_refreshed wc_fragments_loaded updated_checkout ppcp_cc_block_ready ppcp_cc_checkout_updated update_checkout wpg_change_method';
            $(document.body).on(eventSelectors, (event) => {
                this.debouncedUpdatePaypalCheckout();
                if (this.ppcp_manager.enabled_google_pay === 'yes') {
                    this.debouncedUpdateGooglePay();
                }
                if (this.ppcp_manager.enabled_apple_pay === 'yes') {
                    this.debouncedUpdateApplePay();
                }
            });
            if (this.ppcp_manager.advanced_card_payments === 'yes') {
                $(document.body).on(checkoutSelectors, () => {
                    this.debouncedUpdatePaypalCC();
                });
            }

        }

        handleCheckoutSubmit() {
            var selected = $('input[name="wc-wpg_paypal_checkout_cc-payment-token"]:checked').val();
            if (selected && selected !== 'new') {
                return true; // only return true for saved token (not for 'new')
            }
            if (this.isPpcpCCSelected() && this.isCardFieldEligible()) {
                if ($('form.checkout').hasClass('paypal_cc_submitting')) {
                    return false;
                }
                $('form.checkout').addClass('paypal_cc_submitting');
                $(document.body).trigger('submit_paypal_cc_form');
                return false;
            }
            return true;
        }

        syncPayPalCheckoutButtons() {
            this.ppcp_cart_css();
            this.renderSmartButton();
            if ($('#ppcp_checkout_top').length === 0) {
                const $applePay = $('div.apple-pay-container[data-context="express_checkout"]');
                const $googlePay = $('div.google-pay-container[data-context="express_checkout"]');
                const hasAppleOnly = $applePay.length > 0 && $googlePay.length === 0;
                const hasGoogleOnly = $googlePay.length > 0 && $applePay.length === 0;
                if (hasAppleOnly && !$applePay.hasClass('mobile')) {
                    $applePay.css('min-width', '480px');
                }
                if (hasGoogleOnly && !$googlePay.hasClass('mobile')) {
                    $googlePay.css('min-width', '480px');
                }
            }

        }

        syncPayPalCardFields() {
            if (this.isCardFieldEligible()) {
                this.renderCardFields();
                $('#place_order, .wc-block-components-checkout-place-order-button').show();
            } else {
                $('.wc_payment_method.payment_method_wpg_paypal_checkout_cc').hide();
                $('#radio-control-wc-payment-method-options-wpg_paypal_checkout_cc').parent('label').parent('div').hide();
                if (this.isPpcpCCSelected())
                    $('#payment_method_wpg_paypal_checkout').prop('checked', true).trigger('click');
            }

        }

        isPpcpSelected() {
            if (this.ppcp_manager.is_wpg_change_payment_method === 'yes') {
                return false;
            }
            return $('#payment_method_wpg_paypal_checkout').is(':checked') || $('input[name="radio-control-wc-payment-method-options"]:checked').val() === 'wpg_paypal_checkout';
        }

        isPpcpCCSelected() {
            return $('#payment_method_wpg_paypal_checkout_cc').is(':checked') || $('input[name="radio-control-wc-payment-method-options"]:checked').val() === 'wpg_paypal_checkout_cc';
        }

        isCardFieldEligible() {
            return this.isCheckoutPage() && this.ppcp_manager.advanced_card_payments === 'yes' && typeof wpg_paypal_sdk !== 'undefined' && wpg_paypal_sdk.CardFields().isEligible();
        }

        togglePlaceOrderButton() {
            const isPpcpSelected = this.isPpcpSelected();
            const isPpcpCCSelected = this.isPpcpCCSelected();
            const usePlaceOrder = this.ppcp_manager.use_place_order === '1';
            const PO_CLASSIC = '#place_order';
            const PO_BLOCKS = '.wc-block-components-checkout-place-order-button';
            const WALLETS = '#ppcp_checkout, #ppcp_order_pay, .google-pay-container.checkout, .apple-pay-container.checkout';
            const setVisible = (sel, visible, displayShown = '') => {
                const $el = jQuery(sel);
                $el.toggleClass('wpg_place_order_hide', !visible);
                $el.css('display', visible ? (displayShown || '') : 'none');
            };
            const showPO = () => {
                setVisible(PO_CLASSIC, true, 'inline-block');
                setVisible(PO_BLOCKS, true, 'inline-flex');
            };
            const hidePO = () => {
                setVisible(PO_CLASSIC, false);
                setVisible(PO_BLOCKS, false);
            };
            const showWallets = () => setVisible(WALLETS, true);
            const hideWallets = () => setVisible(WALLETS, false);
            if (isPpcpSelected) {
                if (usePlaceOrder) {
                    hideWallets();
                    showPO();
                } else {
                    hidePO();
                    showWallets();
                }
            } else {
                showPO();
                hideWallets();
            }
            if (isPpcpCCSelected && this.isCardFieldEligible()) {
                showPO();
                hideWallets();
            }
        }

        onShippingChange(data, actions) {
            if (!data || !data.shipping_address) {
                return actions.reject();
            }

            // Simple address mapping (same as before)
            const shippingAddress = {
                city: data.shipping_address.city || '',
                state: data.shipping_address.state || '',
                countryCode: data.shipping_address.country_code || '',
                postalCode: data.shipping_address.postal_code || ''
            };

            // NEW: detect which shipping method was selected in the PayPal UI
            const selectedOption =
                data.selected_shipping_option ||
                data.selectedShippingOption ||
                null;

            const selectedShippingId =
                selectedOption && selectedOption.id ? selectedOption.id : '';

            // Validate address via AJAX (this will also update PayPal order)
            return fetch(this.ppcp_manager.ajax_url, {
                method: 'POST',
                headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                body: new URLSearchParams({
                    action: 'ppcp_validate_shipping_address',
                    security: this.ppcp_manager.ajax_nonce,
                    shipping_address: JSON.stringify(shippingAddress),
                    // NEW: send selected shipping method id to PHP
                    selected_shipping_id: selectedShippingId
                })
            })
                .then(res => res.json())
                .then(result => {
                    if (result && result.success) {
                        return actions.resolve();
                    } else {
                        return actions.reject();
                    }
                })
                .catch(() => {
                    return actions.reject();
                });
        }


        renderSmartButton() {
            const selectors = this.ppcp_manager.button_selector;
            $.each(selectors, (key, selector) => {
                const elements = jQuery(".ppcp-button-container.ppcp_mini_cart");
                if (elements.length > 1) {
                    elements.slice(0, -1).remove();
                }
                if (!$(selector).length || $(selector).children().length || typeof wpg_paypal_sdk === 'undefined') {
                    return;
                }
                const isExpressCheckout = selector === '#ppcp_checkout_top';
                const isMiniCart = selector === '#ppcp_mini_cart';
                const ppcpStyle = {
                    layout: isMiniCart
                            ? this.ppcp_manager.mini_cart_style_layout
                            : (isExpressCheckout ? this.ppcp_manager.express_checkout_style_layout : this.ppcp_manager.style_layout),
                    color: isMiniCart
                            ? this.ppcp_manager.mini_cart_style_color
                            : (isExpressCheckout ? this.ppcp_manager.express_checkout_style_color : this.ppcp_manager.style_color),
                    shape: isMiniCart
                            ? this.ppcp_manager.mini_cart_style_shape
                            : (isExpressCheckout ? this.ppcp_manager.express_checkout_style_shape : this.ppcp_manager.style_shape),
                    label: isMiniCart
                            ? this.ppcp_manager.mini_cart_style_label
                            : (isExpressCheckout ? this.ppcp_manager.express_checkout_style_label : this.ppcp_manager.style_label),
                    height: Number(
                            isExpressCheckout
                            ? this.ppcp_manager.express_checkout_button_height
                            : isMiniCart
                            ? this.ppcp_manager.mini_cart_button_height
                            : this.ppcp_manager.button_height
                            ) || 48
                };
                if (ppcpStyle.layout === 'horizontal') {
                    ppcpStyle.tagline = 'false';
                }
                const baseH = parseFloat(ppcpStyle.height) || 48;       // handles "48" or "48px"
                const heightPx = `${Math.max(0, baseH - 1)}px`;         // reduce by 1px (no negatives)

                const targets = [];
                if (isMiniCart || selector === '#ppcp_cart') {
                    targets.push('#ppcp_cart', '.google-pay-container.cart', '.apple-pay-container.cart');
                } else if (isExpressCheckout) {
                    targets.push('#ppcp_checkout_top', '#ppcp_checkout_top_alternative',
                            '.google-pay-container.express_checkout', '.apple-pay-container.express_checkout');
                } else if (selector === '#ppcp_product') {
                    targets.push('#ppcp_product', '.google-pay-container.product', '.apple-pay-container.product');
                } else if (selector === '#ppcp_checkout') {
                    targets.push('#ppcp_checkout', '.google-pay-container.checkout', '.apple-pay-container.checkout');
                }

                if (targets.length) {
                    document.querySelectorAll(targets.join(',')).forEach(el => {
                        el.style.setProperty('--button-height', heightPx);
                    });
                }

                const styledFundingSources = [
                    wpg_paypal_sdk.FUNDING.PAYPAL,
                    wpg_paypal_sdk.FUNDING.PAYLATER
                ];

                const addShippingCallbacks = selector !== '#ppcp_checkout';

                if (selector === '#ppcp_checkout') {
                    let fundingSources = wpg_paypal_sdk.getFundingSources();
                    if (fundingSources.length) {
                        const hideTagline = this.ppcp_manager.is_google_pay_enabled_checkout === 'yes' || this.ppcp_manager.is_apple_pay_enable_checkout === 'yes';
                        fundingSources.forEach((fundingSource) => {
                            if (fundingSource === wpg_paypal_sdk.FUNDING.CARD && this.isCardFieldEligible()) {
                                return;
                            }
                            const options = {
                                fundingSource,
                                onClick: async (data, actions) => {
                                    this.ppcp_used_payment_method = fundingSource;

                                    if (this.ppcp_manager.is_block_enable === 'yes' && window.wp?.data) {
                                        const vDisp = wp.data.dispatch('wc/store/validation');
                                        const vSel = wp.data.select('wc/store/validation');
                                        const cartSel = wp.data.select('wc/store/cart');
                                        const chkSel = wp.data.select('wc/store/checkout');

                                        // 0) Wait until Blocks is idle (addresses/rates/coupons/customer updates)
                                        const waitUntilIdle = async () => {
                                            for (let i = 0; i < 30; i++) {
                                                const busy =
                                                        cartSel?.isLoading?.() ||
                                                        cartSel?.isCouponsUpdating?.() ||
                                                        cartSel?.isCustomerDataUpdating?.() ||
                                                        chkSel?.isProcessing?.(); // some builds expose this
                                                if (!busy)
                                                    return;
                                                await new Promise(r => setTimeout(r, 50));
                                            }
                                        };
                                        await waitUntilIdle();

                                        // 1) Ask Blocks to reveal native messages
                                        vDisp.showAllValidationErrors();

                                        // 2) Give the validation store a tick to recalc & render
                                        await new Promise(r => setTimeout(r, 0));

                                        // 3) Re-check using BOTH the boolean and the map (some builds lag the boolean)
                                        const hasErrorsBool =
                                                typeof vSel.hasValidationErrors === 'function' && vSel.hasValidationErrors();
                                        const errorMap = typeof vSel.getValidationErrorMap === 'function'
                                                ? vSel.getValidationErrorMap()
                                                : {};
                                        const hasErrors = hasErrorsBool || (errorMap && Object.keys(errorMap).length > 0);

                                        if (hasErrors) {
                                            // keep focus on form; errors are already shown natively
                                            return actions?.reject ? actions.reject() : false;
                                        }
                                    }

                                    // proceed to wallet
                                    return true;
                                }
                                ,
                                createOrder: () => this.createOrder(selector),
                                onApprove: (data, actions) => this.onApproveHandler(data, actions),
                                onCancel: () => this.onCancelHandler(),
                                onError: (err) => this.onErrorHandler(err)
                            };
                            let style = {...ppcpStyle};
                            if (hideTagline) {
                                style.tagline = 'false';
                                const {layout, ...base} = style;
                                style = base; // remove layout
                            }
                            let cleanStyleBase = {...style};
                            if (styledFundingSources.includes(fundingSource)) {
                                options.style = {...cleanStyleBase};
                            } else {
                                const {color, ...cleanStyle} = cleanStyleBase;
                                options.style = {...cleanStyle};
                            }
                            const button = wpg_paypal_sdk.Buttons(options);
                            if (button.isEligible()) {
                                button.render(selector);
                            }
                        });
                    }
                } else if (selector === '#ppcp_checkout_top') {

                    const expressFundingSources = [
                        wpg_paypal_sdk.FUNDING.PAYPAL,
                        wpg_paypal_sdk.FUNDING.VENMO,
                        wpg_paypal_sdk.FUNDING.PAYLATER,
                        wpg_paypal_sdk.FUNDING.CREDIT
                    ];
                    const renderSelectors = ['#ppcp_checkout_top', '#ppcp_checkout_top_alternative'];
                    let renderedCount = 0;
                    for (let i = 0; i < expressFundingSources.length; i++) {
                        const fundingSource = expressFundingSources[i];
                        const targetSelector = renderSelectors[renderedCount];
                        if (!targetSelector || !$(targetSelector).length) {
                            continue;
                        }
                        const {layout, ...cleanStyle} = ppcpStyle;
                        let style = {...cleanStyle};
                        if (fundingSource === wpg_paypal_sdk.FUNDING.VENMO) {
                            style = {
                                ...style,
                                color: 'blue'
                            };
                        } else if (fundingSource === wpg_paypal_sdk.FUNDING.CREDIT) {
                            style = {
                                ...style,
                                color: 'darkblue'
                            };
                        }
                        const options = {
                            style,
                            fundingSource,
                            createOrder: () => this.createOrder(targetSelector),
                            onApprove: (data, actions) => this.onApproveHandler(data, actions),
                            onCancel: () => this.onCancelHandler(),
                            onError: (err) => this.onErrorHandler(err),
                            // Add this line only:
                            onShippingChange: addShippingCallbacks ? (data, actions) => this.onShippingChange(data, actions) : null
                        };
                        const button = wpg_paypal_sdk.Buttons(options);
                        if (button.isEligible()) {
                            button.render(targetSelector);
                            renderedCount++;
                        }
                        if (renderedCount >= 2) {
                            break;
                        }
                    }
                    if (renderedCount < 2 && $('#ppcp_checkout_top_alternative').length) {
                        if ($('div.apple-pay-container[data-context="express_checkout"]').length === 0 && $('div.google-pay-container[data-context="express_checkout"]').length === 0) {
                            if ($('#ppcp_checkout_top').length && !$('#ppcp_checkout_top').hasClass('mobile')) {
                                $('#ppcp_checkout_top').css('min-width', '480px');
                            }
                        }
                        $('#ppcp_checkout_top_alternative').remove();
                    }

                } else {
                    const buttonOptions = {
                        style: ppcpStyle,
                        createOrder: () => this.createOrder(selector),
                        onApprove: (data, actions) => this.onApproveHandler(data, actions),
                        onCancel: () => this.onCancelHandler(),
                        onError: (err) => this.onErrorHandler(err)
                    };
                    if (addShippingCallbacks) {
                        buttonOptions.onShippingChange = (data, actions) => this.onShippingChange(data, actions);
                    }
                    wpg_paypal_sdk.Buttons(buttonOptions).render(selector);
                }
            });
            var $targets = $('#ppcp_product, #ppcp_cart, #ppcp_mini_cart, #ppcp_checkout, #ppcp_checkout_top, #ppcp_checkout_top_alternative');
            setTimeout(function () {
                $targets.css({background: '', 'background-color': ''});
                $targets.each(function () {
                    this.style.setProperty('--wpg-skel-fallback-bg', 'transparent');
                });
                $targets.addClass('bg-cleared');
            }, 1);
        }
        
        getFromValue(selector) {
            if (selector === '#ppcp_product') return 'product';
            if (selector === '#ppcp_cart') return 'cart';
            if (selector === '#ppcp_checkout_top') return 'express_checkout';
            if (selector === '#ppcp_checkout') return 'checkout';
            if (selector === '#ppcp_order_pay') return 'pay_page';

            return 'checkout'; // fallback default
        }

        createOrder(selector) {
            this.showSpinner();
            $('.woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message, .is-error, .is-success').remove();
            let data;
            if (selector === '#ppcp_checkout_top') {
            } else if (this.isCheckoutPage()) {
                data = $(selector).closest('form').serialize();
                if (this.ppcp_manager.is_block_enable === 'yes') {
                    const notes = jQuery('.wc-block-components-textarea').val() || '';
                    data += '&customer_note=' + encodeURIComponent(notes);
                    const billingAddress = this.getBillingAddress();
                    const shippingAddress = this.getShippingAddress();
                    data += '&billing_address=' + encodeURIComponent(JSON.stringify(billingAddress));
                    data += '&shipping_address=' + encodeURIComponent(JSON.stringify(shippingAddress));
                    data += `&woocommerce-process-checkout-nonce=${this.ppcp_manager.woocommerce_process_checkout}`;
                }
            } else if (this.isProductPage()) {
                $('<input>', {type: 'hidden', name: 'ppcp-add-to-cart', value: $("[name='add-to-cart']").val()}).appendTo('form.cart');
                data = $('form.cart').serialize();
            } else {
                data = $('form.woocommerce-cart-form').serialize();
            }

            const fundingMethod = this.ppcp_used_payment_method;
            const from = this.getFromValue(selector);

            let createOrderUrl = this.ppcp_manager.create_order_url_for_paypal
                .replace(/([?&])from=[^&]*/i, '$1') // remove old `from`
                .replace(/[?&]$/, '');              // cleanup

            createOrderUrl += (createOrderUrl.includes('?') ? '&' : '?')
                + 'from=' + from
                + '&ppcp_used_payment_method=' + encodeURIComponent(fundingMethod);
        
            return fetch(createOrderUrl, {
                method: 'POST',
                headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                body: data
            }).then(res => res.json()).then(data => {
                this.hideSpinner();
                if (data.success !== undefined) {
                    const messages = data.data.messages ?? data.data;
                    this.showError(messages);
                    return null;
                }
                return data.orderID;
            });
        }

        googleapplecreateOrder() {
            this.showSpinner();
            $('.woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message, .is-error, .is-success').remove();
            let data = '';
            switch (this.pageContext) {
                case 'checkout':
                    const selector = `[data-context="${this.pageContext}"]`;
                    data = $(selector).closest('form').serialize();
                    const isBlockCheckout = this.ppcp_manager.is_block_enable === 'yes';
                    if (isBlockCheckout && $('form.wc-block-checkout__form').length) {
                        const notes = jQuery('.wc-block-components-textarea').val() || '';
                        data += '&customer_note=' + encodeURIComponent(notes);
                        let billingAddress = this.getBillingAddress();
                        let shippingAddress = this.getShippingAddress();
                        // User-entered Block Checkout fields take precedence. Only fall back to
                        // the wallet address when the customer clicked an express wallet button
                        // without filling in the form, otherwise the WC order is created blank.
                        if ((!billingAddress || !billingAddress.billing_address_1) && this.walletBillingAddress) {
                            const walletBilling = this.walletToWCFormat(this.walletBillingAddress, 'billing');
                            if (walletBilling.billing_address_1) {
                                billingAddress = walletBilling;
                            }
                        }
                        if ((!shippingAddress || !shippingAddress.shipping_address_1) && this.walletShippingAddress) {
                            const walletShipping = this.walletToWCFormat(this.walletShippingAddress, 'shipping');
                            if (walletShipping.shipping_address_1) {
                                shippingAddress = walletShipping;
                            }
                        }
                        data += '&billing_address=' + encodeURIComponent(JSON.stringify(billingAddress));
                        data += '&shipping_address=' + encodeURIComponent(JSON.stringify(shippingAddress));
                        data += `&woocommerce-process-checkout-nonce=${this.ppcp_manager.woocommerce_process_checkout}`;
                    } else if ($('form.checkout').length) {
                        data = $('form.checkout').serialize();
                    } else if ($('form.woocommerce-cart-form').length) {
                        data = $('form.woocommerce-cart-form').serialize();
                    }
                    break;
                case 'express_checkout':
                case 'product':
                    break;
                default:
                    data = $('form.woocommerce-cart-form').serialize();
                    break;
            }
            
            let createOrderUrl = this.ppcp_manager.create_order_url_for_google_pay;

    createOrderUrl = createOrderUrl
        .replace(/([?&])from=[^&]*/i, '$1') 
        .replace(/[?&]$/, '');                

    createOrderUrl += (createOrderUrl.includes('?') ? '&' : '?')
        + 'from=' + encodeURIComponent(this.pageContext); 

            return fetch(createOrderUrl, {
                method: 'POST',
                headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                body: data
            }).then(res => res.json()).then(data => {
                this.hideSpinner();
                if (data.success !== undefined && data.success === false) {
                    const messages = typeof data.data === 'string'
                            ? data.data
                            : (data.data.messages ?? 'An unknown error occurred.');

                    this.showError(messages);
                    throw new Error(messages);
                    return null;
                }
                return data.orderID;
            });
        }

        onApproveHandler(data, actions) {
            this.showSpinner();
            const order_id = data.orderID || data.orderId || '';
            const payer_id = data.payerID || data.payerId || '';
            if (!order_id) {
                return;
            }
            if (this.isCheckoutPage() || this.ppcp_manager.skip_order_review === 'yes') {
                const url = `${this.ppcp_manager.cc_capture}&paypal_order_id=${encodeURIComponent(order_id)}&woocommerce-process-checkout-nonce=${this.ppcp_manager.woocommerce_process_checkout}`;
                $.post(url, (response) => {
                    if (response?.data?.redirect) {
                        window.location.href = response.data.redirect;
                    } else {
                        if (response?.success === false) {
                            const messages = response.data?.messages ?? ['An unknown error occurred.'];
                            this.showError(messages);
                            this.hideSpinner();
                            let redirectUrl = `${this.ppcp_manager.checkout_url}?paypal_order_id=${encodeURIComponent(order_id)}&from=${this.ppcp_manager.page}`;
                            if (payer_id) {
                                redirectUrl += `&paypal_payer_id=${encodeURIComponent(payer_id)}`;
                            }
                            window.location.href = redirectUrl;
                        }
                    }
                });
                return;
            }
            let redirectUrl = `${this.ppcp_manager.checkout_url}?paypal_order_id=${encodeURIComponent(order_id)}&from=${this.ppcp_manager.page}`;
            if (payer_id) {
                redirectUrl += `&paypal_payer_id=${encodeURIComponent(payer_id)}`;
            }
            window.location.href = redirectUrl;
        }

        showSpinner(containerSelector = '.woocommerce') {
            if (jQuery('.wc-block-checkout__main').length || jQuery('.wp-block-woocommerce-cart').length) {
                jQuery('.wc-block-checkout__main, .wp-block-woocommerce-cart').block({message: null, overlayCSS: {background: '#fff', opacity: 0.6}});
            } else if (jQuery('form.checkout').length) {
                jQuery('form.checkout').block({message: null, overlayCSS: {background: '#fff', opacity: 0.6}});
            } else if (jQuery(containerSelector).length) {
                jQuery(containerSelector).block({message: null, overlayCSS: {background: '#fff', opacity: 0.6}});
            }
            
            if (jQuery('#wfacp-sec-wrapper').length) {
                jQuery('#wfacp-sec-wrapper').block({message: null, overlayCSS: {background: '#fff', opacity: 0.6}});
            }
        }

        hideSpinner(containerSelector = '.woocommerce') {
            if (jQuery('.wc-block-checkout__main').length || jQuery('.wp-block-woocommerce-cart').length) {
                jQuery('.wc-block-checkout__main, .wp-block-woocommerce-cart').unblock();
            } else if (jQuery('form.checkout').length) {
                jQuery('form.checkout').unblock();
            } else if (jQuery(containerSelector).length) {
                jQuery(containerSelector).unblock();
            }
            
            if (jQuery('#wfacp-sec-wrapper').length) {
                jQuery('#wfacp-sec-wrapper').unblock();
            }
        }

        onCancelHandler() {
            window.location.reload(true);
            this.hideSpinner();
        }

        onErrorHandler(err) {
            this.hideSpinner();
        }

        showError(error_message) {
            if (typeof error_message === 'undefined' || error_message === null) {
                return;
            }
            let $checkout_form;
            if ($('form.checkout').length) {
                $checkout_form = $('form.checkout');
            } else if ($('.woocommerce-notices-wrapper').length) {
                $checkout_form = $('.woocommerce-notices-wrapper');
            } else if ($('.woocommerce').length) {
                $checkout_form = $('.woocommerce');
            } else if ($('.wc-block-components-notices').length) {
                $checkout_form = $('.wc-block-components-notices').first();
            } else if ($('form#wfacp_checkout_form').length) {
                $checkout_form = $('form#wfacp_checkout_form').first();
            }
            if ($checkout_form && $checkout_form.length) {
                $('.woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message, .is-error, .is-success').remove();
                if (!error_message || (typeof error_message !== 'string' && !Array.isArray(error_message))) {
                    error_message = ['An unknown error occurred.'];
                } else if (typeof error_message === 'string') {
                    error_message = [error_message];
                } else if (error_message?.data?.messages && Array.isArray(error_message.data.messages)) {
                    error_message = error_message.data.messages;
                }
                let errorHTML = '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout" role="alert" aria-live="assertive"><ul class="woocommerce-error">';
                $.each(error_message, (index, value) => {
                    errorHTML += `<li>${value}</li>`;
                });
                errorHTML += '</ul></div>';
                $checkout_form.prepend(errorHTML).removeClass('processing').unblock();
                $checkout_form.find('.input-text, select, input:checkbox').trigger('validate').trigger('blur');
                const scrollElement = $('.woocommerce-NoticeGroup-updateOrderReview, .woocommerce-NoticeGroup-checkout').filter(function () {
                    const $el = $(this);
                    if (!$el.length || !$el.is(':visible')) {
                        return false;
                    }
                    const offset = $el.offset?.();
                    return offset && typeof offset.top !== 'undefined';
                }).first();
                if (scrollElement.length) {
                    const offset = scrollElement.offset();
                    if (offset && typeof offset.top !== 'undefined') {
                        $('html, body').animate({scrollTop: offset.top - 100}, 1000);
                    }
                }
                //$(document.body).trigger('checkout_error', [error_message]);
            } else {
                const errorMessagesString = Array.isArray(error_message)
                        ? error_message.join('<br>')
                        : typeof error_message === 'string'
                        ? error_message
                        : 'An unknown error occurred.';

                $(document.body).trigger('ppcp_checkout_error', errorMessagesString);
            }
        }

        renderCardFields() {
            jQuery(document.body).trigger('wc-credit-card-form-init');
            const checkoutSelector = this.getCheckoutSelectorCss();
            if ($('#wpg_paypal_checkout_cc-card-number').length === 0 || typeof wpg_paypal_sdk === 'undefined') {
                return;
            }
            $(checkoutSelector).addClass('CardFields');
            const cardStyle = {
                input: {fontSize: '18px', fontFamily: 'Helvetica, Arial, sans-serif', fontWeight: '400', color: '#32325d', padding: '12px 14px', borderRadius: '4px', border: '1px solid #ccd0d5', background: '#ffffff', boxShadow: 'none', transition: 'border-color 0.15s ease, box-shadow 0.15s ease'},
                '.invalid': {color: '#fa755a', border: '1px solid #fa755a', boxShadow: 'none'},
                '::placeholder': {color: '#aab7c4'},
                'input:focus': {outline: 'none', border: '1px solid #4a90e2', boxShadow: '0 0 4px rgba(74, 144, 226, 0.3)'},
                '.valid': {border: '1px solid #3ac569', color: '#32325d', boxShadow: 'none'}
            };
            const cardFields = wpg_paypal_sdk.CardFields({
                style: cardStyle,
                createOrder: () => this.createCardOrder(checkoutSelector),
                onApprove: (payload) => payload && payload.orderID ? this.submitCardFields(payload) : console.error("No valid payload returned during onApprove:", payload),
                onError: (err) => {
                    this.handleCardFieldsError(err, checkoutSelector);
                }
            });
            if (cardFields.isEligible()) {
                if (($("#wpg_paypal_checkout_cc-card-number").html() || "").trim() === "") {
                    const numberField = cardFields.NumberField();
                    $("#wpg_paypal_checkout_cc-card-number").empty();
                    $("#wpg_paypal_checkout_cc-card-expiry").empty();
                    $("#wpg_paypal_checkout_cc-card-cvc").empty();
                    numberField.render("#wpg_paypal_checkout_cc-card-number");
                    numberField.setAttribute("placeholder", "1234 1234 1234 1234");
                    cardFields.ExpiryField().render("#wpg_paypal_checkout_cc-card-expiry");
                    cardFields.CVVField().render("#wpg_paypal_checkout_cc-card-cvc");
                }
                setTimeout(function () {
                    $('.wpg-paypal-cc-field label, .wpg-ppcp-card-cvv-icon').show();
                }, 1600);
                setTimeout(function () {
                    $('.wpg_ppcp_sanbdox_notice').show();
                }, 1900);
            } else {
                console.log('Advanced Card Payments not Eligible', cardFields.isEligible());
                $('.payment_box.payment_method_wpg_paypal_checkout_cc').hide();
                if (this.isPpcpCCSelected()) {
                    $('#payment_method_wpg_paypal_checkout').prop('checked', true).trigger('click');
                }
            }
            $(document.body).on('submit_paypal_cc_form', () => {
                cardFields.submit().catch((error) => {
                    this.handleCardFieldsError(error, checkoutSelector);
                });
            });
        }

        createCardOrder(checkoutSelector) {
            this.showSpinner();
            $('.woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message, .is-error, .is-success').remove();
            let data;
            if (this.ppcp_manager.is_block_enable === 'yes') {
                data = $('form.wc-block-checkout__form').serialize();
                const notes = jQuery('.wc-block-components-textarea').val() || '';
                data += '&customer_note=' + encodeURIComponent(notes);
                const billingAddress = this.getBillingAddress();
                const shippingAddress = this.getShippingAddress();
                data += '&billing_address=' + encodeURIComponent(JSON.stringify(billingAddress));
                data += '&shipping_address=' + encodeURIComponent(JSON.stringify(shippingAddress));
                data += `&woocommerce-process-checkout-nonce=${this.ppcp_manager.woocommerce_process_checkout}`;
            } else {
                data = $(checkoutSelector).closest('form').serialize();
            }
            return fetch(this.ppcp_manager.create_order_url_for_cc, {
                method: 'POST',
                headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                body: data
            })
                    .then(res => res.json())
                    .then(data => {
                        if (!data || data.success === false) {
                            const messages = data.data.messages ?? data.data;
                            this.hideSpinner();
                            this.showError(messages || 'An unknown error occurred while creating the order.');
                            return Promise.reject();
                        }
                        return data.orderID;
                    })
                    .catch(err => {
                        this.hideSpinner();
                        return Promise.reject();
                    });
        }

        submitCardFields(payload) {
            $.post(`${this.ppcp_manager.cc_capture}&paypal_order_id=${payload.orderID}&woocommerce-process-checkout-nonce=${this.ppcp_manager.woocommerce_process_checkout}`, (data) => {
                window.location.href = data.data.redirect;
            });
        }

        handleCardFieldsError(errorString, checkoutSelector) {
            $('#place_order, #wc-wpg_paypal_checkout-cc-form').unblock();
            $(checkoutSelector).removeClass('processing paypal_cc_submitting CardFields createOrder').unblock();

            const t = (key, fallback) => {
              const v = (this.ppcp_manager && this.ppcp_manager[key]) ? String(this.ppcp_manager[key]) : '';
              return v ? v : fallback;
            };

            const UNKNOWN_FALLBACK = "An unknown error occurred with your payment. Please try again.";
            const INVALID_NUM_FALLBACK = "Please enter a valid card number.";
            const INVALID_CVV_FALLBACK = "Please enter a valid CVV.";
            const INVALID_EXP_FALLBACK = "Please enter a valid expiration date.";

            let message = t('unknown_error', UNKNOWN_FALLBACK);

            let raw = errorString instanceof Error ? errorString.message : String(errorString);
            if (raw.includes('Expected reject')) {
              return true;
            }

            try {
              if (raw.includes('INVALID_NUMBER')) {
                message = t('invalid_number', INVALID_NUM_FALLBACK);
              } else if (raw.includes('INVALID_CVV')) {
                message = t('invalid_cvv', INVALID_CVV_FALLBACK);
              } else if (raw.includes('INVALID_EXPIRATION') || raw.includes('INVALID_EXPIRY_DATE')) {
                message = t('invalid_expiry', INVALID_EXP_FALLBACK);
              } else {
                const jsonStart = raw.indexOf('{');
                const jsonEnd = raw.lastIndexOf('}') + 1;

                if (jsonStart !== -1 && jsonEnd !== -1 && jsonEnd > jsonStart) {
                  const jsonString = raw.slice(jsonStart, jsonEnd);
                  const error = JSON.parse(jsonString);

                  if (
                    (error.message && error.message.includes('Expected reject')) ||
                    (error.details?.[0]?.description && error.details[0].description.includes('Expected reject'))
                  ) {
                    return true;
                  }

                  if (error.success === false && error.data && error.data.messages && Array.isArray(error.data.messages)) {
                    if (error.data.messages.some(msg => msg.includes('Expected reject'))) {
                      return true;
                    }
                    message = error.data.messages
                      .map(msg => msg.replace(/<\/?[^>]+(>|$)/g, ''))
                      .join('\n');

                  } else if (error.details && Array.isArray(error.details)) {
                    const cardError = error.details.find(detail =>
                      detail.issue === 'VALIDATION_ERROR' ||
                      detail.issue === 'INVALID_NUMBER' ||
                      detail.issue === 'INVALID_CVV' ||
                      detail.issue === 'INVALID_EXPIRY_DATE' ||
                      detail.field?.includes('/card/')
                    );

                    if (cardError) {
                      switch (cardError.issue) {
                        case 'INVALID_NUMBER':
                          message = t('invalid_number', INVALID_NUM_FALLBACK);
                          break;
                        case 'INVALID_CVV':
                          message = t('invalid_cvv', INVALID_CVV_FALLBACK);
                          break;
                        case 'INVALID_EXPIRY_DATE':
                          message = t('invalid_expiry', INVALID_EXP_FALLBACK);
                          break;
                        case 'VALIDATION_ERROR':
                          if (cardError.field?.includes('/card/number')) {
                            message = t('invalid_number', INVALID_NUM_FALLBACK);
                          } else if (cardError.field?.includes('/card/expiry')) {
                            message = t('invalid_expiry', INVALID_EXP_FALLBACK);
                          } else if (cardError.field?.includes('/card/security_code')) {
                            message = t('invalid_cvv', INVALID_CVV_FALLBACK);
                          }
                          break;
                      }
                    }
                  }

                  // If still default unknown message, try PayPal-provided message
                  if (message === t('unknown_error', UNKNOWN_FALLBACK)) {
                    if (error.details?.[0]?.description) {
                      message = error.details[0].description;
                    } else if (error.message) {
                      message = error.message;
                    }
                  }
                }
              }
            } catch (err) {
              if (raw.includes('INVALID_NUMBER')) {
                message = t('invalid_number', INVALID_NUM_FALLBACK);
              } else if (raw.includes('INVALID_CVV')) {
                message = t('invalid_cvv', INVALID_CVV_FALLBACK);
              } else if (raw.includes('INVALID_EXPIRATION') || raw.includes('INVALID_EXPIRY_DATE')) {
                message = t('invalid_expiry', INVALID_EXP_FALLBACK);
              } else {
                const lastColon = raw.lastIndexOf(':');
                message = lastColon > 0 ? raw.slice(lastColon + 1).trim() : raw;
              }
            }

            message = String(message || '').replace(/\.$/, '').trim();
            this.showError(message);
            this.hideSpinner();
            return false;
          }

        getCheckoutSelectorCss() {
            return this.isCheckoutPage() ? 'form.checkout' : 'form.cart';
        }

        isCCPaymentMethodSelected() {
            return this.getSelectedPaymentMethod() === 'wpg_paypal_checkout_cc';
        }

        getSelectedPaymentMethod() {
            return $('input[name="payment_method"]:checked').val();
        }

        ppcp_cart_css() {
            $('.payment_box.payment_method_wpg_paypal_checkout').each(function () {
                if (($(this).html() || '').trim() === '') {
                    $(this).hide();
                }
            });
        }

        manageVariations(selector) {
            if ($('.variations_form').length) {
                $('.variations_form, .single_variation').on('show_variation', function (event, variation) {
                    if (variation.is_purchasable && variation.is_in_stock) {
                        $(selector).show();
                    } else {
                        $(selector).hide();
                    }
                }).on('hide_variation', function () {
                    $(selector).hide();
                });
            }
        }

        isPayPalGooglePaySdkReady() {
            return typeof wpg_paypal_sdk !== "undefined" && typeof wpg_paypal_sdk.Googlepay !== "undefined" && typeof google !== "undefined";
        }

        removeGooglePayContainer() {
            const containers = document.querySelectorAll('.google-pay-container');
            containers.forEach(container => {
                container.remove();
            });
        }

        getGooglePaymentsClient( { requireOnPaymentDataChanged = false } = {}) {
            if (typeof google === "undefined") {
                return null;
            }
            if (!this.paymentsClient || this.paymentsClientRequiresDataChanged !== requireOnPaymentDataChanged) {
                const paymentDataCallbacks = {
                    onPaymentAuthorized: this.onPaymentAuthorized.bind(this)
                };
                if (requireOnPaymentDataChanged) {
                    paymentDataCallbacks.onPaymentDataChanged = this.onPaymentDataChanged.bind(this);
                }
                this.paymentsClient = new google.payments.api.PaymentsClient({
                    environment: this.ppcp_manager.environment || "TEST",
                    paymentDataCallbacks
                });
                this.paymentsClientRequiresDataChanged = requireOnPaymentDataChanged;
            }
            return this.paymentsClient;
        }

        async onPaymentDataChanged(intermediatePaymentData) {
            try {
                const {callbackTrigger, shippingAddress, shippingOptionData} = intermediatePaymentData || {};
                const mapAddr = (addr = {}) => ({
                    address1: addr.address1 || '',
                    address2: addr.address2 || '',
                    city: addr.locality || '',
                    state: addr.administrativeArea || '',
                    postcode: addr.postalCode || '',
                    country: addr.countryCode || ''
                });
                if (callbackTrigger === 'INITIALIZE') {
                    if (shippingAddress) {
                        const mapped = mapAddr(shippingAddress);
                        const vr = await this.validateShippingAddressFromBackend({
                            city: mapped.city,
                            state: mapped.state,
                            countryCode: mapped.country,
                            postalCode: mapped.postcode
                        });
                        if (!vr || vr.success !== true) {
                            const msg = (vr && vr.data) ? String(vr.data) : this.t('shipping_unserviceable', 'We do not ship to this address.');
                            return {
                                error: {
                                    reason: 'SHIPPING_ADDRESS_UNSERVICEABLE',
                                    message: msg,
                                    intent: 'SHIPPING_ADDRESS'
                                }
                            };
                        }
                        await this.fetchUpdatedTotalFromBackend(mapped);
                        const tx = this.getGoogleTransactionInfo();
                        tx.totalPriceStatus = 'ESTIMATED';
                        return {
                            newTransactionInfo: tx,
                            newShippingOptionParameters: this.getGoogleShippingOptionParametersOrPlaceholder()
                        };
                    }
                    return {};
                }
                if (callbackTrigger === 'SHIPPING_ADDRESS' && shippingAddress) {
                    const selectedShippingId = shippingOptionData && shippingOptionData.id ? shippingOptionData.id : '';
                    const mapped = mapAddr(shippingAddress);
                    const vr = await this.validateShippingAddressFromBackend({
                        city: mapped.city,
                        state: mapped.state,
                        countryCode: mapped.country,
                        postalCode: mapped.postcode
                    }, selectedShippingId);
                    if (!vr || vr.success !== true) {
                        const msg = (vr && vr.data) ? String(vr.data) : this.t('shipping_unserviceable', 'We do not ship to this address.');
                        return {
                            error: {
                                reason: 'SHIPPING_ADDRESS_UNSERVICEABLE',
                                message: msg,
                                intent: 'SHIPPING_ADDRESS'
                            }
                        };
                    }
                    await this.fetchUpdatedTotalFromBackend(mapped, null, selectedShippingId);
                    const tx = this.getGoogleTransactionInfo();
                    tx.totalPriceStatus = 'ESTIMATED';
                    return {
                        newTransactionInfo: tx,
                        newShippingOptionParameters: this.getGoogleShippingOptionParametersOrPlaceholder()
                    };
                }
                if (callbackTrigger === 'SHIPPING_OPTION' && shippingOptionData && shippingOptionData.id) {
                    if (shippingOptionData.id === 'pending') {
                        const tx = this.getGoogleTransactionInfo();
                        tx.totalPriceStatus = 'ESTIMATED';
                        return {
                            newTransactionInfo: tx,
                            newShippingOptionParameters: this.getGoogleShippingOptionParametersOrPlaceholder()
                        };
                    }
                    const safeId = shippingOptionData.id;
                    const internalId = (this.googleShippingIdMap && this.googleShippingIdMap[safeId]) ? this.googleShippingIdMap[safeId] : safeId;
                    this.googleSelectedShippingId = internalId;
                    const addr = shippingAddress ? mapAddr(shippingAddress) : {};
                    await this.fetchUpdatedTotalFromBackend(addr, null, internalId);
                    const tx = this.getGoogleTransactionInfo();
                    tx.totalPriceStatus = 'ESTIMATED';
                    return {
                        newTransactionInfo: tx,
                        newShippingOptionParameters: this.getGoogleShippingOptionParametersOrPlaceholder()
                    };
                }
                return {};
            } catch (e) {
                console.error('onPaymentDataChanged error:', e);
                return {};
            }
        }

        async getGooglePayConfig() {
            try {
                if (!this.allowedPaymentMethods || !this.merchantInfo) {
                    const googlePayConfig = await wpg_paypal_sdk.Googlepay().config();
                    let methods = googlePayConfig.allowedPaymentMethods || [];
                    methods = methods.map(method => {
                        const m = { ...method };
                        m.parameters = { ...(m.parameters || {}) };
                        m.parameters.billingAddressRequired = true;
                        m.parameters.billingAddressParameters = {
                            ...(m.parameters.billingAddressParameters || {}),
                            phoneNumberRequired: true,
                        };
                        return m;
                    });
                    this.allowedPaymentMethods = methods;
                    this.merchantInfo = googlePayConfig.merchantInfo || {};
                }
                return {
                    allowedPaymentMethods: this.allowedPaymentMethods,
                    merchantInfo: this.merchantInfo,
                };
            } catch (error) {
                console.error("Failed to fetch Google Pay configuration:", error);
                return { allowedPaymentMethods: [], merchantInfo: {} };
            }
        }

        getGoogleIsReadyToPayRequest(allowedPaymentMethods) {
            return {
                apiVersion: 2,
                apiVersionMinor: 0,
                allowedPaymentMethods,
            };
        }

        async syncGooglePayButton() {
            if (this.ppcp_manager.enabled_google_pay !== 'yes') {
                this.removeGooglePayContainer();
                return;
            }
            if (!this.isPayPalGooglePaySdkReady()) {
                console.log('[Google Pay] SDK not available (script not loaded or unsupported)');
                this.removeGooglePayContainer();
                return;
            }
            const googlePayConfig = await this.getGooglePayConfig();
            const allowedPaymentMethods = googlePayConfig?.allowedPaymentMethods;
            if (!allowedPaymentMethods || !allowedPaymentMethods.length) {
                console.log('[Google Pay] No allowed payment methods');
                this.removeGooglePayContainer();
                return;
            }
            const shippingRequired = this.ppcp_manager.needs_shipping === "1";
            const paymentsClient = this.getGooglePaymentsClient({requireOnPaymentDataChanged: shippingRequired});
            try {
                const response = await paymentsClient.isReadyToPay(this.getGoogleIsReadyToPayRequest(allowedPaymentMethods));
                if (!response.result) {
                    console.log('[Google Pay] isReadyToPay returned false');
                    this.removeGooglePayContainer();
                    return;
                }
                document.querySelectorAll('.google-pay-container').forEach(container => {
                    container.innerHTML = '';
                    this.renderGooglePayButton(container);
                });
            } catch (error) {
                console.error('[Google Pay] isReadyToPay failed', error);
                this.removeGooglePayContainer();
            }
        }

        renderGooglePayButton(container) {
            if (!container) {
                return;
            }
            const context = container.getAttribute('data-context') || 'product';
            const labelMap = {
                product: this.ppcp_manager.google_pay_style_label,
                cart: this.ppcp_manager.google_pay_style_label,
                checkout: this.ppcp_manager.google_pay_style_label,
                express_checkout: this.ppcp_manager.google_pay_express_checkout_style_label,
                mini_cart: this.ppcp_manager.google_pay_mini_cart_style_label
            };
            const colorMap = {
                product: this.ppcp_manager.google_pay_style_color,
                cart: this.ppcp_manager.google_pay_style_color,
                checkout: this.ppcp_manager.google_pay_style_color,
                express_checkout: this.ppcp_manager.google_pay_express_checkout_style_color,
                mini_cart: this.ppcp_manager.google_pay_mini_cart_style_color
            };
            const shapeMap = {
                product: this.ppcp_manager.google_pay_style_shape,
                cart: this.ppcp_manager.google_pay_style_shape,
                checkout: this.ppcp_manager.google_pay_style_shape,
                express_checkout: this.ppcp_manager.google_pay_express_checkout_style_shape,
                mini_cart: this.ppcp_manager.google_pay_mini_cart_style_shape
            };
            const heightMap = {
                product: this.ppcp_manager.button_height,
                cart: this.ppcp_manager.button_height,
                checkout: this.ppcp_manager.button_height,
                express_checkout: this.ppcp_manager.express_checkout_button_height,
                mini_cart: this.ppcp_manager.mini_cart_button_height
            };
            const buttonType = labelMap[context] || 'plain';
            const buttonColor = colorMap[context] || 'black';
            const buttonShape = shapeMap[context] || 'rect';
            const buttonHeight = parseInt(heightMap[context]) || 40;
            let buttonRadius;
            if (buttonShape === 'rect') {
                buttonRadius = 4;
            } else {
                buttonRadius = Math.round(buttonHeight / 2);
            }
            const paymentsClient = this.getGooglePaymentsClient();
            const button = paymentsClient.createButton({
                buttonColor: buttonColor,
                buttonType: buttonType,
                buttonRadius: buttonRadius,
                buttonLocale: this.ppcp_manager.locale,
                buttonSizeMode: 'fill',
                onClick: this.onGooglePaymentButtonClicked.bind(this)
            });
            button.setAttribute('data-context', context);
            container.innerHTML = '';
            container.appendChild(button);
            button.querySelector('.gpay-button').style.setProperty('border-radius', `${buttonRadius}px`, 'important');
            var $targets = $('.google-pay-container');
            setTimeout(function () {
                $targets.css({background: '', 'background-color': ''});
                $targets.each(function () {
                    this.style.setProperty('--wpg-skel-fallback-bg', 'transparent');
                });
                $targets.addClass('bg-cleared');
            }, 1);
        }

        async onGooglePaymentButtonClicked(event) {
            try {
                this.showSpinner();
                const button = event?.target?.closest('button');
                const clickedWrapper = button?.parentElement;
                this.pageContext = clickedWrapper?.getAttribute('data-context') || 'unknown';
                const transactionInfo = await this.ppcpGettransactionInfo();
                if (transactionInfo?.success === false) {
                    const messages = transactionInfo.data?.messages ?? transactionInfo.data ?? ['Unknown error'];
                    this.showError(messages);
                    this.hideSpinner();
                    throw new Error(messages);
                }
                if (transactionInfo?.success && transactionInfo.data) {
                    if (typeof this.setTotalsFromResponse === 'function') {
                        this.setTotalsFromResponse(transactionInfo.data);
                    }
                }
                const shippingRequired = this.ppcp_manager.needs_shipping === "1" && this.pageContext !== 'checkout';
                const paymentsClient = this.getGooglePaymentsClient({requireOnPaymentDataChanged: shippingRequired});
                const paymentDataRequest = await this.getGooglePaymentDataRequest();
                await paymentsClient.loadPaymentData(paymentDataRequest);
            } catch (error) {
                console.error('[GPay] loadPaymentData error:', error);
                this.hideSpinner();
                if (error?.statusCode === "CANCELED") {
                    window.location.reload(true);
                    console.warn("Google Pay was cancelled by the user.");
                    return;
                }
                console.error("Google Pay Button Click Error:", error);
            }
        }

        getGoogleShippingOptionParameters() {
            const methods = Array.isArray(this.ppcp_manager.shipping_methods) ? this.ppcp_manager.shipping_methods : [];
            if (!methods.length) {
                return null;
            }
            this.googleShippingIdMap = {};
            const formatPrice = (amount) => {
                const n = parseFloat(String(amount || "0").replace(/,/g, "")) || 0;
                const currency = this.ppcp_manager.currency || "USD";
                const locale   = this.ppcp_manager.locale   || "en-US";
                return new Intl.NumberFormat(locale, {
                    style: "currency",
                    currency
                }).format(n);
            };
            let defaultInternalId = this.googleSelectedShippingId;
            if (!defaultInternalId) {
                const selected = methods.find(m => m.is_selected);
                defaultInternalId = selected?.id || methods[0].id;
            }
            const options = methods.map(method => {
                const internalId = method.id;
                const safeId = internalId.replace(/[^a-zA-Z0-9 _-]/g, "_");
                this.googleShippingIdMap[safeId] = internalId;
                const formattedAmount = formatPrice(method.amount);
                return {
                    id: safeId,
                    label: method.label || internalId,
                    description: formattedAmount
                };
            });
            let defaultSafeId = options[0].id;
            const found = options.find(opt => this.googleShippingIdMap[opt.id] === defaultInternalId);
            if (found) defaultSafeId = found.id;
            return {
                defaultSelectedOptionId: defaultSafeId,
                shippingOptions: options
            };
        }

        getGoogleShippingOptionParametersOrPlaceholder() {
            const real = this.getGoogleShippingOptionParameters();
            if (real && Array.isArray(real.shippingOptions) && real.shippingOptions.length > 0) {
                return real;
            }
            return {
                defaultSelectedOptionId: 'pending',
                shippingOptions: [{
                    id: 'pending',
                    label: this.t('calculating_shipping', 'Shipping'),
                    description: this.t('calculating_shipping_desc', 'Calculated after address selection')
                }]
            };
        }

        async getGooglePaymentDataRequest() {
            const {allowedPaymentMethods, merchantInfo} = await this.getGooglePayConfig();
            const shippingRequired = this.ppcp_manager.needs_shipping === "1" && this.pageContext !== 'checkout';
            const callbackIntents = ['PAYMENT_AUTHORIZATION'];
            if (shippingRequired) {
                callbackIntents.push('SHIPPING_ADDRESS', 'SHIPPING_OPTION');
            }
            const paymentDataRequest = {
                apiVersion: 2,
                apiVersionMinor: 0,
                allowedPaymentMethods,
                transactionInfo: this.getGoogleTransactionInfo(),
                merchantInfo,
                emailRequired: true,
                callbackIntents
            };
            if (shippingRequired) {
                paymentDataRequest.shippingAddressRequired = true;
                paymentDataRequest.shippingAddressParameters = {
                    phoneNumberRequired: true
                };
                paymentDataRequest.shippingOptionRequired = true;
                paymentDataRequest.shippingOptionParameters = this.getGoogleShippingOptionParametersOrPlaceholder();
            }
            return paymentDataRequest;
        }

        async ppcpGettransactionInfo() {
            try {
                this.showSpinner();
                $('.woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message, .is-error, .is-success').remove();
                let data = '';
                const isBlockCheckout = this.ppcp_manager.is_block_enable === 'yes';
                switch (this.pageContext) {
                    case 'checkout':
                        data = isBlockCheckout ? $('form.wc-block-checkout__form').serialize() : $('form.checkout').serialize();
                        if (isBlockCheckout) {
                            const billingAddress = this.getBillingAddress();
                            const shippingAddress = this.getShippingAddress();
                            data += '&billing_address=' + encodeURIComponent(JSON.stringify(billingAddress));
                            data += '&shipping_address=' + encodeURIComponent(JSON.stringify(shippingAddress));
                            data += `&woocommerce-process-checkout-nonce=${this.ppcp_manager.woocommerce_process_checkout}`;
                        }
                        break;
                    case 'product':
                        $('<input>', {
                            type: 'hidden',
                            name: 'ppcp-add-to-cart',
                            value: $("[name='add-to-cart']").val()
                        }).appendTo('form.cart');
                        data = $('form.cart').serialize();
                        break;
                    case 'express_checkout':
                        break;
                    default:
                        data = $('form.woocommerce-cart-form').serialize();
                        break;
                }
                const transactionInfoUrl = `${this.ppcp_manager.get_transaction_info_url}&form=${encodeURIComponent(this.pageContext)}&used=google_pay`;
                const response = await fetch(transactionInfoUrl, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                    body: data
                });
                return await response.json();
            } catch (error) {
                console.error('Error in ppcpGettransactionInfo:', error);
                return null;
            } finally {
                this.hideSpinner();
            }
        }

        getGoogleTransactionInfo() {
            const currency = this.ppcp_manager?.currency || "USD";
            const country  = this.ppcp_manager?.country  || "US";
            const toNum = (v) => {
                const f = parseFloat((v ?? "").toString().replace(/,/g, ""));
                return Number.isFinite(f) ? f : 0;
            };
            const toStr = (v) => toNum(v).toFixed(2);
            const displayItems = [];
            const items = Array.isArray(this.ppcp_manager?.cart_items) ? this.ppcp_manager.cart_items : [];
            for (const it of items) {
                const name = it?.name ?? "Item";
                const qty  = Math.max(1, parseInt(it?.quantity, 10) || 1);
                const lineTotal = ("subtotal" in it) ? toNum(it.subtotal) : toNum(it.price) * qty;
                displayItems.push({
                    label: `${name}${qty > 1 ? ` × ${qty}` : ""}`,
                    type: "LINE_ITEM",
                    price: toStr(lineTotal)
                });
            }
            const needsShipping = String(this.ppcp_manager?.needs_shipping ?? "0") === "1";
            const shippingTotal = toNum(this.ppcp_manager?.shipping_total);
            if (needsShipping && shippingTotal > 0) {
                displayItems.push({
                    label: "Shipping",
                    type: "SHIPPING_OPTION",
                    price: toStr(shippingTotal)
                });
            }
            const taxTotal = toNum(this.ppcp_manager?.tax_total);
            if (taxTotal > 0) {
                displayItems.push({
                    label: "Tax",
                    type: "TAX",
                    price: toStr(taxTotal)
                });
            }
            const discountTotal = toNum(this.ppcp_manager?.discount_total);
            if (discountTotal > 0) {
                displayItems.push({
                    label: "Discount",
                    type: "DISCOUNT",
                    price: toStr(-discountTotal)
                });
            }
            const total = toNum(this.ppcp_manager?.cart_total);
            return {
                displayItems,
                currencyCode: currency,
                countryCode: country,
                totalPriceStatus: "ESTIMATED",
                totalPrice: toStr(total),
                totalPriceLabel: "Total",
                checkoutOption: "DEFAULT"
            };
        }

        async onPaymentAuthorized(paymentData) {
            try {
                // Always extract wallet addresses so googleapplecreateOrder() can use them
                // as a fallback when the Block Checkout form has not been filled.
                const billingRaw  = paymentData?.paymentMethodData?.info?.billingAddress || {};
                const shippingRaw = paymentData?.shippingAddress || {};
                const email       = paymentData?.email || '';
                const billingAddress = {
                    name:         billingRaw.name || '',
                    surname:      '',
                    address1:     billingRaw.address1 || '',
                    address2:     billingRaw.address2 || '',
                    city:         billingRaw.locality || '',
                    state:        billingRaw.administrativeArea || '',
                    postcode:     billingRaw.postalCode || '',
                    country:      billingRaw.countryCode || '',
                    phoneNumber:  billingRaw.phoneNumber || '',
                    emailAddress: email || ''
                };
                const shippingAddress = {
                    name:        shippingRaw.name || '',
                    surname:     '',
                    address1:    shippingRaw.address1 || '',
                    address2:    shippingRaw.address2 || '',
                    city:        shippingRaw.locality || '',
                    state:       shippingRaw.administrativeArea || '',
                    postcode:    shippingRaw.postalCode || '',
                    country:     shippingRaw.countryCode || '',
                    phoneNumber: shippingRaw.phoneNumber || ''
                };
                this.walletBillingAddress = billingAddress;
                this.walletShippingAddress = shippingAddress;
                if (this.pageContext !== 'checkout') {
                    await this.fetchUpdatedTotalFromBackend(shippingAddress, billingAddress);
                }
                if (this.googleSelectedShippingId === 'pending' || !this.googleSelectedShippingId) {
                    const methods = Array.isArray(this.ppcp_manager.shipping_methods) ? this.ppcp_manager.shipping_methods : [];
                    if (methods.length) {
                        const pick = methods.find(m => m.is_selected) || methods[0];
                        this.googleSelectedShippingId = pick.id;
                    }
                }
                const orderId = await this.googleapplecreateOrder();
                if (!orderId) {
                    throw new Error("Order creation failed.");
                }
                const result = await wpg_paypal_sdk.Googlepay().confirmOrder({
                    orderId,
                    paymentMethodData: paymentData.paymentMethodData
                }).catch(err => {
                    console.error('[Google Pay] confirmOrder error:', err);
                    throw err;
                });
                if (result && result.status === "PAYER_ACTION_REQUIRED") {
                    await wpg_paypal_sdk.Googlepay().initiatePayerAction({ orderId });
                }
                this.onApproveHandler({ orderID: orderId }, 'google_pay');
                return { transactionState: "SUCCESS" };
            } catch (error) {
                this.showError(error.message || "Google Pay failed.");
                this.hideSpinner();
                return {
                    transactionState: "ERROR",
                    error: {
                        intent: "PAYMENT_AUTHORIZATION",
                        message: error.message || "Google Pay failed."
                    }
                };
            }
        }

        setTotalsFromResponse(d = {}) {
            if (!d) {
                return;
            }

            this.ppcp_manager.cart_total       = d.total          ?? d.cart_total ?? this.ppcp_manager.cart_total;
            this.ppcp_manager.cart_items       = Array.isArray(d.cart_items) ? d.cart_items : (this.ppcp_manager.cart_items || []);
            this.ppcp_manager.shipping_total   = d.shipping_total ?? this.ppcp_manager.shipping_total ?? "0.00";
            this.ppcp_manager.tax_total        = d.tax_total      ?? this.ppcp_manager.tax_total      ?? "0.00";
            this.ppcp_manager.discount_total   = d.discount_total ?? this.ppcp_manager.discount_total ?? "0.00";
            this.ppcp_manager.currency         = d.currency       ?? this.ppcp_manager.currency;
            this.ppcp_manager.needs_shipping   = d.needs_shipping ?? this.ppcp_manager.needs_shipping ?? "0";
            this.ppcp_manager.shipping_methods = Array.isArray(d.shipping_methods)
                ? d.shipping_methods
                : (this.ppcp_manager.shipping_methods || []);

            const selected = (this.ppcp_manager.shipping_methods || []).find(m => m.is_selected);
            if (selected && selected.id) {
                this.googleSelectedShippingId = selected.id;
                this.appleSelectedShippingId  = selected.id;
            }
        }

        
        async validateShippingAddressFromBackend(shippingAddress, selectedShippingId = '') {
            const params = new URLSearchParams({
                action: 'ppcp_validate_shipping_address',
                security: this.ppcp_manager.ajax_nonce,
                shipping_address: JSON.stringify(shippingAddress || {})
            });
            if (selectedShippingId) {
                params.append('selected_shipping_id', selectedShippingId);
            }
            const res = await fetch(this.ppcp_manager.ajax_url, {
                method: 'POST',
                headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                body: params
            });
            // admin-ajax.php always returns 200, so parse body
            const result = await res.json().catch(() => null);
            return result;
        }

        async fetchUpdatedTotalFromBackend(shippingAddress, billingAddress = null, selectedShippingId = '') {
            try {
                const params = new URLSearchParams({
                    action: 'ppcp_get_updated_total',
                    security: this.ppcp_manager.ajax_nonce,
                    shipping_address: JSON.stringify(shippingAddress || {}),
                    billing_address: billingAddress ? JSON.stringify(billingAddress) : '',
                    context: this.pageContext
                });
                if (selectedShippingId) {
                    params.append('selected_shipping_id', selectedShippingId);
                }
                const res = await fetch(this.ppcp_manager.ajax_url, {
                    method: 'POST',
                    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                    body: params
                });
                const result = await res.json();
                if (result?.success && result.data) {
                    if (typeof this.setTotalsFromResponse === 'function') {
                        this.setTotalsFromResponse(result.data);
                    }
                    if (result.data.total != null) {
                        const n = parseFloat(String(result.data.total).replace(/,/g, ''));
                        return Number.isFinite(n) ? n.toFixed(2) : String(result.data.total);
                    }
                }
                const n = parseFloat(String(this.ppcp_manager.cart_total || '0').replace(/,/g, ''));
                return Number.isFinite(n) ? n.toFixed(2) : (this.ppcp_manager.cart_total || '0.00');
            } catch (e) {
                console.error('Error fetching updated total:', e);
                const n = parseFloat(String(this.ppcp_manager.cart_total || '0').replace(/,/g, ''));
                return Number.isFinite(n) ? n.toFixed(2) : (this.ppcp_manager.cart_total || '0.00');
            }
        }

        formatAmount(amount) {
            if (typeof amount === 'number') {
                return amount.toFixed(2);
            }
            if (typeof amount === 'string') {
                const parsed = parseFloat(amount);
                return isNaN(parsed) ? "0.00" : parsed.toFixed(2);
            }
            return "0.00";
        }

        prefetchProductTotal() {
            const isApplePayEnabled = this.ppcp_manager?.enabled_apple_pay === 'yes';
            const hasApplePayContainer = document.querySelector('.apple-pay-container');
            if (!isApplePayEnabled || !hasApplePayContainer) {
                return;
            }
            const isProductPage = document.querySelector('.apple-pay-container[data-context="product"]');
            if (isProductPage) {
                const getCurrentProductId = () => {
                    const variationInput = document.querySelector('input.variation_id');
                    const variationId = parseInt(variationInput?.value || 0, 10);
                    return variationId > 0
                        ? variationId
                        : parseInt(this.ppcp_manager?.product_id || 0, 10);
                };
                const getQty = () => parseFloat(document.querySelector('input.qty')?.value || '1') || 1;
                const baseProductId = getCurrentProductId();
                const defaultQty = getQty();
                this.fetchProductTotal(baseProductId, defaultQty);
                jQuery('form.variations_form').off('found_variation.wpg_ap').on('found_variation.wpg_ap', (event, variation) => {
                    const variationId = parseInt(variation?.variation_id || 0, 10) || getCurrentProductId();
                    this.fetchProductTotal(variationId, getQty());
                });
                jQuery(document).off('change.wpg_ap_qty input.wpg_ap_qty', 'input.qty')
                    .on('change.wpg_ap_qty input.wpg_ap_qty', 'input.qty', () => {
                        this.fetchProductTotal(getCurrentProductId(), getQty());
                });
            } else {
                this.fetchProductTotal(0, 0);
            }
        }

        fetchProductTotal(productId, quantity = 1) {
            const data = new URLSearchParams({
                action: 'ppcp_get_product_total',
                security: this.ppcp_manager.ajax_nonce,
                product_id: productId,
                quantity: quantity
            });

            fetch(this.ppcp_manager.ajax_url, {
                method: 'POST',
                headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                body: data.toString()
            }).then(res => res.json())
            .then(response => {
                if (response.success && response.data?.combined_total) {
                    this.ppcp_manager.cart_total = response.data.combined_total;
                }
            });
        }

        removeApplePayContainer() {
            setTimeout(() => {
                const containers = document.querySelectorAll('.apple-pay-container');
                containers.forEach(container => {
                    container.remove();
                });
            }, 500);
        }

        async syncApplePayButton() {
            if (this.ppcp_manager.enabled_apple_pay !== 'yes') {
                this.removeApplePayContainer();
                return;
            }
            if (window.location.protocol !== 'https:') {
                console.log("Apple Pay requires HTTPS. Current protocol:", window.location.protocol);
                this.removeApplePayContainer();
                return;
            }
            if (!window.ApplePaySession) {
                console.log("Apple Pay is not supported on this device.");
                this.removeApplePayContainer();
                return;
            }
            if (!ApplePaySession.canMakePayments()) {
                console.log("Apple Pay cannot make payments on this device.");
                this.removeApplePayContainer();
                return;
            }
            if (typeof wpg_paypal_sdk === 'undefined' || typeof wpg_paypal_sdk.Applepay !== 'function') {
                this.removeApplePayContainer();
                return;
            }
            try {
                const applepay = wpg_paypal_sdk.Applepay();
                const config = await applepay.config({ environment: this.ppcp_manager.environment || "TEST" });
                if (config && config.isEligible) {
                    this.renderApplePayButton();
                } else {
                    console.log("Apple Pay is not eligible for this configuration.");
                    this.removeApplePayContainer();
                }
            } catch (error) {
                console.error("Failed to load Apple Pay configuration:", error);
                this.removeApplePayContainer();
            }
        }

        renderApplePayButton() {
            const containers = document.querySelectorAll(".apple-pay-container");
            if (containers.length === 0) {
                return;
            }
            this.prefetchProductTotal();
            containers.forEach(container => {
                container.innerHTML = '';
                const applePayButton = document.createElement('apple-pay-button');
                const context = container.getAttribute('data-context') || 'product';
                const labelMap = {
                    product: this.ppcp_manager.apple_pay_style_label,
                    cart: this.ppcp_manager.apple_pay_style_label,
                    checkout: this.ppcp_manager.apple_pay_style_label,
                    express_checkout: this.ppcp_manager.apple_pay_express_checkout_style_label,
                    mini_cart: this.ppcp_manager.apple_pay_mini_cart_style_label
                };
                const colorMap = {
                    product: this.ppcp_manager.apple_pay_style_color,
                    cart: this.ppcp_manager.apple_pay_style_color,
                    checkout: this.ppcp_manager.apple_pay_style_color,
                    express_checkout: this.ppcp_manager.apple_pay_express_checkout_style_color,
                    mini_cart: this.ppcp_manager.apple_pay_mini_cart_style_color
                };
                const heightMap = {
                    product: this.ppcp_manager.button_height,
                    cart: this.ppcp_manager.button_height,
                    checkout: this.ppcp_manager.button_height,
                    express_checkout: this.ppcp_manager.express_checkout_button_height,
                    mini_cart: this.ppcp_manager.mini_cart_button_height
                };
                const shapeMap = {
                    product: this.ppcp_manager.apple_pay_style_shape,
                    cart: this.ppcp_manager.apple_pay_style_shape,
                    checkout: this.ppcp_manager.apple_pay_style_shape,
                    express_checkout: this.ppcp_manager.apple_pay_express_checkout_style_shape,
                    mini_cart: this.ppcp_manager.apple_pay_mini_cart_style_shape
                };
                const buttonType = labelMap[context] || 'plain';
                const buttonColor = colorMap[context] || 'black';
                const buttonHeight = parseInt(heightMap[context]) || 40;
                const buttonShape = shapeMap[context] || 'rect';
                const buttonRadius = buttonShape === 'pill' ? 20 : 4;

                container.classList.add(buttonShape === 'pill' ? 'apple-shape-pill' : 'apple-shape-rect');

                container.style.setProperty('--button-height', `${buttonHeight}px`);
                container.style.setProperty('--button-radius', `${buttonRadius}px`);
                container.style.height = `${buttonHeight}px`;

                applePayButton.setAttribute('type', buttonType);
                applePayButton.setAttribute('buttonstyle', buttonColor);
                applePayButton.setAttribute('data-context', context);
                container.appendChild(applePayButton);
                applePayButton.addEventListener('click', () => this.onApplePayButtonClicked(container));
                var $targets = $('.apple-pay-container');
                setTimeout(function () {
                    $targets.css({background: '', 'background-color': ''});
                    $targets.each(function () {
                        this.style.setProperty('--wpg-skel-fallback-bg', 'transparent');
                    });
                    $targets.addClass('bg-cleared');
                }, 1);
            });
        }
        
        getAppleShippingMethods() {
            const methods = Array.isArray(this.ppcp_manager.shipping_methods) ? this.ppcp_manager.shipping_methods : [];
            if (!methods.length) {
                return [];
            }
            this.appleShippingIdMap = {};
            let defaultInternalId = this.appleSelectedShippingId;
            if (!defaultInternalId) {
                const selected = methods.find(m => m.is_selected);
                defaultInternalId = (selected && selected.id) ? selected.id : methods[0].id;
            }
            this.appleSelectedShippingId = defaultInternalId;

            const appleMethods = methods.map(method => {
                const internalId = method.id;
                const safeId = internalId.replace(/[^a-zA-Z0-9 _-]/g, "_");
                this.appleShippingIdMap[safeId] = internalId;

                return {
                    label: method.label || internalId,
                    amount: this.formatAmount(method.amount),
                    identifier: safeId,
                    detail: method.description || ''
                };
            });
            return appleMethods;
        }

        onApplePayButtonClicked(container) {
            try {
                this.showSpinner();
                this.pageContext = container?.getAttribute('data-context') || 'unknown';
                if (!window.ApplePaySession || !ApplePaySession.canMakePayments()) {
                    console.warn('Apple Pay is not available on this device or browser.');
                    this.hideSpinner();
                    return;
                }
                const applepay = wpg_paypal_sdk.Applepay();
                const needsShipping = this.ppcp_manager.needs_shipping === "1" && this.pageContext !== 'checkout';
                const paymentRequest = {
                    countryCode: this.ppcp_manager.country || "US",
                    currencyCode: this.ppcp_manager.currency || "USD",
                    supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
                    merchantCapabilities: ['supports3DS'],
                    requiredBillingContactFields: ["postalAddress", "email", "phone", "name"],
                    total: {
                        label: this.ppcp_manager.store_label || "Total",
                        amount: this.formatAmount(this.ppcp_manager.cart_total),
                        type: "final"
                    }
                };
                if (needsShipping) {
                    paymentRequest.requiredShippingContactFields = ["postalAddress", "name", "phone", "email"];
                    const methods = this.getAppleShippingMethods();
                    if (methods.length) {
                        paymentRequest.shippingMethods = methods;
                    } else {
                        paymentRequest.shippingMethods = [{
                            label: 'Shipping',
                            amount: '0.00',
                            identifier: 'pending',
                            detail: 'Calculated after address selection'
                        }];
                    }
                } else {
                    paymentRequest.requiredShippingContactFields = ["name", "phone", "email"];
                }

                const session = new ApplePaySession(4, paymentRequest);
                session.onvalidatemerchant = async (event) => {
                    try {
                        const validation = await applepay.validateMerchant({
                            validationUrl: event.validationURL,
                            displayName: this.ppcp_manager.store_label || "Store"
                        });
                        session.completeMerchantValidation(validation.merchantSession);
                    } catch (err) {
                        console.error('Merchant validation failed:', err);
                        session.abort();
                        this.hideSpinner();
                    }
                };

                if (needsShipping) {
                    session.onshippingcontactselected = async (event) => {
                        try {
                            if (this.pageContext === 'product') {
                                const transactionInfo = await this.ppcpGettransactionInfo();
                                if (transactionInfo?.success === false) {
                                    const messages = transactionInfo.data?.messages ?? transactionInfo.data ?? ['Unknown error'];
                                    this.showError(messages);
                                    throw new Error(messages);
                                    session.completePayment({
                                        status: ApplePaySession.STATUS_FAILURE
                                    });
                                }
                                if (transactionInfo?.success && transactionInfo.data && typeof this.setTotalsFromResponse === 'function') {
                                    this.setTotalsFromResponse(transactionInfo.data);
                                }
                            }

                            const shipping = event.shippingContact;
                            if (!shipping || !shipping.countryCode || !shipping.postalCode) {
                                throw new Error(this.t('shipping_address_incomplete', 'Shipping address is incomplete.'));
                            }

                            // ✅ Validate shipping country/address via the same AJAX endpoint used by PayPal onShippingChange
                            const vr = await this.validateShippingAddressFromBackend({
                                city: shipping.locality || '',
                                state: shipping.administrativeArea || '',
                                countryCode: shipping.countryCode || '',
                                postalCode: shipping.postalCode || ''
                            });
                            if (!vr || vr.success !== true) {
                                const msg = (vr && vr.data) ? String(vr.data) : this.t('shipping_unserviceable', 'We do not ship to this address.');
                                const errors = [];
                                if (window.ApplePayError) {
                                    errors.push(new ApplePayError('shippingContactInvalid', 'postalAddress', msg));
                                }
                                session.completeShippingContactSelection({
                                    errors,
                                    newTotal: {
                                        label: this.ppcp_manager.store_label || "Store",
                                        amount: this.formatAmount(this.ppcp_manager.cart_total),
                                        type: "final"
                                    }
                                });
                                return;
                            }

                            const updatedTotal = await this.fetchUpdatedTotalFromBackend({
                                city:    shipping.locality || '',
                                state:   shipping.administrativeArea || '',
                                postcode: shipping.postalCode || '',
                                country: shipping.countryCode || ''
                            });

                            const methods = this.getAppleShippingMethods();
                            const update = {
                                newTotal: {
                                    label: this.ppcp_manager.store_label || "Store",
                                    amount: updatedTotal,
                                    type: "final"
                                }
                            };

                            if (methods.length) {
                                update.newShippingMethods = methods;
                            }

                            session.completeShippingContactSelection(update);
                        } catch (error) {
                            console.error('[ApplePay] onshippingcontactselected error:', error);
                            const fallbackMethods = this.getAppleShippingMethods();
                            const update = {
                                newTotal: {
                                    label: this.ppcp_manager.store_label || "Store",
                                    amount: this.formatAmount(this.ppcp_manager.cart_total),
                                    type: "final"
                                }
                            };
                            if (fallbackMethods.length) {
                                update.newShippingMethods = fallbackMethods;
                            }
                            session.completeShippingContactSelection(update);
                        }
                    };

                    session.onshippingmethodselected = async (event) => {
                        try {
                            const method = event.shippingMethod;
                            if (!method || !method.identifier) {
                                throw new Error(this.t('invalid_shipping_method', 'Invalid shipping method.'));
                            }
                            if (method.identifier === 'pending') {
                                session.completeShippingMethodSelection({
                                    newTotal: {
                                        label: this.ppcp_manager.store_label || "Store",
                                        amount: this.formatAmount(this.ppcp_manager.cart_total),
                                        type: "final"
                                    }
                                });
                                return;
                            }
                            const internalId = this.appleShippingIdMap[method.identifier] || method.identifier;
                            this.appleSelectedShippingId = internalId;

                            const updatedTotal = await this.fetchUpdatedTotalFromBackend(
                                {}, // shipping address unchanged
                                null, // billing not needed here
                                internalId
                            );

                            const update = {
                                newTotal: {
                                    label: this.ppcp_manager.store_label || "Store",
                                    amount: updatedTotal,
                                    type: "final"
                                }
                            };

                            session.completeShippingMethodSelection(update);
                        } catch (error) {
                            console.error('[ApplePay] onshippingmethodselected error:', error);
                            session.completeShippingMethodSelection({
                                newTotal: {
                                    label: this.ppcp_manager.store_label || "Store",
                                    amount: this.formatAmount(this.ppcp_manager.cart_total),
                                    type: "final"
                                }
                            });
                        }
                    };
                }

                session.onpaymentauthorized = async (event) => {
                    try {
                        
                        const transactionInfo = await this.ppcpGettransactionInfo();
                        if (transactionInfo.success === false) {
                            const messages = transactionInfo.data?.messages ?? transactionInfo.data ?? ['Unknown error'];
                            this.showError(messages);
                            throw new Error(messages);
                            session.completePayment({
                                status: ApplePaySession.STATUS_FAILURE
                            });
                        }
                        if (transactionInfo?.success) {
                            this.ppcp_manager.cart_total = transactionInfo.data?.cart_total || this.ppcp_manager.cart_total;
                        }
                        

                        const billingRaw = event.payment?.billingContact || {};
                        const shippingRaw = event.payment?.shippingContact || {};
                        const emailAddress = billingRaw.emailAddress || shippingRaw.emailAddress || billingRaw.email || shippingRaw.email || '';
                        const billingAddress = {
                            name: billingRaw.givenName || '',
                            surname: billingRaw.familyName || '',
                            address1: billingRaw.addressLines?.[0] || '',
                            address2: billingRaw.addressLines?.[1] || '',
                            city: billingRaw.locality || '',
                            state: billingRaw.administrativeArea || '',
                            postcode: billingRaw.postalCode || '',
                            country: billingRaw.countryCode || '',
                            phoneNumber: billingRaw.phoneNumber || '',
                            emailAddress: emailAddress
                        };
                        const shippingAddress = {
                            name: shippingRaw.givenName || '',
                            surname: shippingRaw.familyName || '',
                            address1: shippingRaw.addressLines?.[0] || '',
                            address2: shippingRaw.addressLines?.[1] || '',
                            city: shippingRaw.locality || '',
                            state: shippingRaw.administrativeArea || '',
                            postcode: shippingRaw.postalCode || '',
                            country: shippingRaw.countryCode || '',
                            phoneNumber: shippingRaw.phoneNumber || ''
                        };
                        // Store wallet addresses so googleapplecreateOrder() can fall back to
                        // them when the Block Checkout form is empty.
                        this.walletBillingAddress = billingAddress;
                        this.walletShippingAddress = shippingAddress;

                        if (needsShipping) {
                            await this.fetchUpdatedTotalFromBackend(
                                shippingAddress,
                                billingAddress,
                                this.appleSelectedShippingId || ''
                            );
                        }

                        const orderId = await this.googleapplecreateOrder();
                        if (!orderId) {
                            throw new Error("Order creation failed.");
                        }

                        const result = await applepay.confirmOrder({
                            orderId: orderId,
                            token: event.payment.token,
                            billingContact: event.payment.billingContact
                        });

                        const status = result?.approveApplePayPayment?.status;
                        if (status === "APPROVED") {
                            this.showSpinner();
                            const order_id = orderId;

                            if (this.isCheckoutPage() || this.ppcp_manager.skip_order_review === 'yes') {
                                const url = `${this.ppcp_manager.cc_capture}&paypal_order_id=${encodeURIComponent(order_id)}&woocommerce-process-checkout-nonce=${this.ppcp_manager.woocommerce_process_checkout}`;
                                $.post(url, (response) => {
                                    if (response?.data?.redirect) {
                                        session.completePayment({
                                            status: ApplePaySession.STATUS_SUCCESS
                                        });
                                        window.location.href = response.data.redirect;
                                    } else {
                                        if (response?.success === false) {
                                            const messages = response.data?.messages ?? [this.t('unknown_error_short', 'An unknown error occurred.')];
                                            this.showError(messages);
                                            let redirectUrl = `${this.ppcp_manager.checkout_url}?paypal_order_id=${encodeURIComponent(order_id)}&from=${this.ppcp_manager.page}`;
                                            window.location.href = redirectUrl;
                                            this.hideSpinner();
                                        }
                                    }
                                });
                            } else {
                                session.completePayment({
                                    status: ApplePaySession.STATUS_SUCCESS
                                });
                                let redirectUrl = `${this.ppcp_manager.checkout_url}?paypal_order_id=${encodeURIComponent(order_id)}&from=${this.ppcp_manager.page}`;
                                window.location.href = redirectUrl;
                                this.hideSpinner();
                            }
                        } else {
                            throw new Error(this.t('apple_pay_not_approved', 'Apple Pay confirmation returned non-APPROVED status.'));
                        }
                    } catch (error) {
                        session.completePayment({
                            status: ApplePaySession.STATUS_FAILURE
                        });
                        this.showError(error?.message || String(error) || 'An unknown error occurred.');
                        this.hideSpinner();
                    }
                };

                session.oncancel = () => {
                    window.location.reload(true);
                    console.log("Apple Pay session cancelled.");
                    this.hideSpinner();
                };
                session.begin();
            } catch (err) {
                console.error('Apple Pay session initialization failed:', err);
                this.showError(this.t('apple_pay_init_failed', 'Apple Pay could not be initialized.'));
                this.hideSpinner();
            }
        }
    }
    $(function () {
        $('.woocommerce #payment #place_order, .woocommerce-page #payment #place_order').hide();
        window.PPCPManager = PPCPManager;
        const ppcp_manager = window.ppcp_manager || {};
        window.ppcpManagerInstance = new PPCPManager(ppcp_manager);
    });
})(jQuery);