/**
 * WooCommerce CAPI Tracker — Frontend Pixel Tracker.
 *
 * Handles: event_id generation (crypto.getRandomValues), sendBeacon with fetch fallback,
 * Set() dedup for race conditions, page-context event firing, Purchase dedup.
 *
 * @package WooCAPITracker
 */
(function () {
    'use strict';

    // ── Config (from wp_localize_script) ──
    var config = window.capiflowConfig || {};
    if (!config.proxyUrl || !config.pixelId) {
        return;
    }

    // ── Cookie Helpers ──
    function getCookie(name) {
        var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
        return match ? decodeURIComponent(match[2]) : '';
    }

    function setCookie(name, value, days) {
        var expires = '';
        if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
            expires = '; expires=' + date.toUTCString();
        }
        document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/; SameSite=Lax';
    }

    // ── Set tracking cookies client-side ──
    // IMPORTANT: Do NOT set _fbp or _fbc here!
    // Meta's fbevents.js SDK is the SOLE owner of these cookies.
    // Setting them manually creates duplicate cookies with different domain scopes,
    // which corrupts the SDK and prevents browser events from being sent.

    // cs_uid — Our own stable user identifier (safe to set).
    if (!getCookie('cs_uid')) {
        var uid = '';
        var arr = new Uint8Array(16);
        crypto.getRandomValues(arr);
        for (var i = 0; i < arr.length; i++) {
            uid += arr[i].toString(16).padStart(2, '0');
        }
        setCookie('cs_uid', uid, 180);
    }

    // ── Client-side Dedup Set (prevents sendBeacon + fallbackFetch race) ──
    var sentEvents = new Set();

    /**
     * Generate a client-side event ID using crypto.getRandomValues().
     * 64-bit entropy = 16 hex chars.
     *
     * @returns {string} Event ID in format: cevt_{hex}_{timestamp}
     */
    function generateEventId() {
        var arr = new Uint8Array(8);
        crypto.getRandomValues(arr);
        var hex = Array.from(arr, function (b) {
            return b.toString(16).padStart(2, '0');
        }).join('');
        return 'cevt_' + hex + '_' + Date.now();
    }

    /**
     * Send tracking data to the REST proxy.
     *
     * Uses sendBeacon (preferred for page unload resilience),
     * with fetch() fallback for older browsers.
     *
     * @param {Object} data - Tracking data payload.
     */
    function sendToProxy(data) {
        // Dedup guard — prevent same event sending twice.
        var dedupKey = data.event_name + '_' + data.event_id;
        if (sentEvents.has(dedupKey)) {
            return;
        }
        sentEvents.add(dedupKey);

        // Fix #2: Merge pre-hashed server PII (generated during PHP page render
        // where is_user_logged_in() is TRUE). Passes through proxy to CAPI
        // for logged-in users, boosting server-side EMQ to match browser EMQ.
        var payloadData = Object.assign({}, data);
        if (config.serverUserData && Object.keys(config.serverUserData).length > 0) {
            payloadData.server_user_data = config.serverUserData;
        }

        var payload = JSON.stringify(payloadData);

        // Attempt sendBeacon first (no nonce needed).
        if (navigator.sendBeacon) {
            var blob = new Blob([payload], { type: 'application/json' });
            var sent = navigator.sendBeacon(config.proxyUrl, blob);
            if (sent) {
                return;
            }
        }

        // Fallback to fetch.
        if (window.fetch) {
            fetch(config.proxyUrl, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: payload,
                keepalive: true,
                credentials: 'same-origin',
            }).catch(function () {
                // Silent fail — fire-and-forget.
            });
            return;
        }

        // Last resort: XHR.
        var xhr = new XMLHttpRequest();
        xhr.open('POST', config.proxyUrl, true);
        xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.send(payload);
    }

    /**
     * Fire a Meta Pixel event (browser-side fbq) + server proxy.
     *
     * @param {string} eventName  - Meta event name.
     * @param {string} eventId    - Shared event ID for dedup.
     * @param {Object} customData - Event custom data.
     */
    function fireEvent(eventName, eventId, customData) {
        // Browser pixel (fbq).
        if (typeof fbq === 'function') {
            fbq('track', eventName, customData || {}, { eventID: eventId });
        }

        // Server proxy.
        sendToProxy({
            event_name: eventName,
            event_id: eventId,
            source_url: window.location.href,
            referrer_url: document.referrer || '',
            custom_data: customData || {},
        });
    }

    // ── PageView ──
    // Browser PageView is fired in <head> via fbq('track','PageView', {}, {eventID}).
    // Use the SAME event_id for server proxy → Meta deduplicates them.
    if (config.eventsConfig && config.eventsConfig.pageview) {
        var pvId = window.capiflowPageViewId || generateEventId();
        sendToProxy({
            event_name: 'PageView',
            event_id: pvId,
            source_url: window.location.href,
            referrer_url: document.referrer || '',
            custom_data: {},
        });
    }

    // ── Deferred AddToCart (from separate PHP-injected JSON) ──
    // Fires browser-only fbq() for AddToCart on redirect target page.
    // CAPI event was already sent via sendBeacon on the original page.
    function handleDeferredAddToCart() {
        var el = document.getElementById('capiflow-deferred-atc');
        if (!el) {
            return;
        }

        try {
            var data = JSON.parse(el.textContent);
            if (!data || data.event !== 'AddToCart') {
                return;
            }

            // Check if AddToCart tracking is enabled.
            if (config.eventsConfig && config.eventsConfig.addtocart === false) {
                return;
            }

            var eventId = data.eventId || generateEventId();

            // Browser pixel only — CAPI already sent via sendBeacon.
            if (typeof fbq === 'function') {
                fbq('track', 'AddToCart', data.custom_data || {}, { eventID: eventId });
            }

            // Clear the cookie so it doesn't persist.
            document.cookie = "capiflow_atc_event_id=; path=/; max-age=0";
        } catch (e) {
            // Silent fail.
        }
    }
    handleDeferredAddToCart();

    // ── Page Context Events (ViewContent, Search, InitiateCheckout — from Pixel Injector inline data) ──
    function handlePageData() {
        var el = document.getElementById('capiflow-page-data');
        if (!el) {
            return;
        }

        try {
            var data = JSON.parse(el.textContent);
            if (!data || !data.event) {
                return;
            }

            var eventName = data.event;
            var eventId = data.eventId || generateEventId();

            // Check if event type is enabled.
            // Map event name to config key (e.g. InitiateCheckout → initiatecheckout).
            var configKey = eventName.toLowerCase().replace(/[^a-z]/g, '');
            if (config.eventsConfig && config.eventsConfig[configKey] === false) {
                return;
            }

            // Normal event — fire both browser pixel and CAPI proxy.
            fireEvent(eventName, eventId, data.custom_data || {});
        } catch (e) {
            // Silent fail.
        }
    }
    handlePageData();

    // ── AddToCart (Universal — Classic + Block Themes) ──
    if (config.eventsConfig && config.eventsConfig.addtocart) {

        /**
         * Resolve the best content_id for a product.
         * Prefer SKU (from PHP skuMap) to match ViewContent/InitiateCheckout.
         * Falls back to numeric product ID if no SKU mapped.
         */
        function resolveContentId(productId) {
            var pid = String(productId);
            if (config.skuMap && config.skuMap[pid]) {
                return config.skuMap[pid];
            }
            return pid;
        }

        /**
         * Extract product ID from a button or form element.
         *
         * Supports ALL WooCommerce themes:
         *   Classic: data-product_id (underscore) on <a>/<li>
         *   Block:   data-product-id (hyphen) on <a>/<div>
         *   Single:  <button name="add-to-cart" value="ID"> or
         *            <input name="product_id" value="ID"> inside form.cart
         *   URL:     ?add-to-cart=ID in the button href
         */
        function extractProductId(btn) {
            // 1. Classic theme: data-product_id (underscore) on button or parent.
            var el = btn.closest('[data-product_id]');
            if (el) {
                return el.getAttribute('data-product_id') || '';
            }

            // 2. Block theme: data-product-id (hyphen) on button or parent.
            var blockEl = btn.closest('[data-product-id]');
            if (blockEl) {
                return blockEl.getAttribute('data-product-id') || '';
            }

            // 3. Block theme: button itself has data-product-id.
            if (btn.hasAttribute('data-product-id')) {
                return btn.getAttribute('data-product-id') || '';
            }

            // 4. URL parsing: href="?add-to-cart=123"
            var href = btn.getAttribute('href') || '';
            if (href) {
                var match = href.match(/[?&]add-to-cart=(\d+)/);
                if (match) {
                    return match[1];
                }
            }

            // 5. Single product page — form.cart hidden inputs.
            var form = btn.closest('form.cart, form.variations_form');
            if (form) {
                // Variable product: prioritize variation_id (set by WooCommerce JS when user selects a variation).
                // variation_id = 0 until a valid variation is selected, then WC updates it dynamically.
                var varInput = form.querySelector('input[name="variation_id"]');
                if (varInput && varInput.value && varInput.value !== '0') {
                    return varInput.value;
                }

                // Fallback: parent product_id (for variable products before variation selection).
                var pidInput = form.querySelector('input[name="product_id"]');
                if (pidInput && pidInput.value) {
                    return pidInput.value;
                }

                // Simple product: <button name="add-to-cart" value="123">
                // or: <input type="hidden" name="add-to-cart" value="123">
                var atcInput = form.querySelector('button[name="add-to-cart"], input[name="add-to-cart"]');
                if (atcInput && atcInput.value) {
                    return atcInput.value;
                }
            }

            return '';
        }

        // Per-product dedup guard — prevents double-fire from click + AJAX handlers.
        var recentAtc = {};

        function fireAddToCartOnce(rawProductId, productName, productPrice, productQty) {
            if (!rawProductId) return;

            // Skip if same product fired within last 2 seconds.
            if (recentAtc[rawProductId]) return;
            recentAtc[rawProductId] = true;
            setTimeout(function () { delete recentAtc[rawProductId]; }, 2000);

            var contentId = resolveContentId(rawProductId);
            var eventId = generateEventId();
            
            // Store event ID in a short-lived cookie. If a form submit causes 
            // a redirect, PHP will read this, store it in WC session, and inject 
            // it on the next page load. This guarantees the deferred browser event 
            // uses the EXACT SAME event_id as the CAPI server event sent via sendBeacon.
            document.cookie = "capiflow_atc_event_id=" + eventId + "; path=/; max-age=60; samesite=lax";

            var qty = parseInt(productQty, 10) || 1;
            var unitPrice = parseFloat(productPrice) || 0;

            fireEvent('AddToCart', eventId, {
                content_ids: [contentId],
                content_type: 'product',
                content_name: productName || '',
                value: unitPrice * qty,
                currency: config.currency || 'BDT',
                contents: [{
                    id: contentId,
                    quantity: qty,
                    item_price: unitPrice
                }],
            });
        }

        // ── All button selectors (classic + block + page builders) ──
        var atcSelectors = [
            '.add_to_cart_button',                              // Classic: shop/archive AJAX
            '.ajax_add_to_cart',                                // Classic: explicit AJAX class
            '.single_add_to_cart_button',                       // Classic: single product
            '.wc-block-components-product-button__button',      // Block theme: product grid
            '.wp-block-button__link[data-product-id]',          // Block theme: linked button
            '.wc-block-components-product-button a',            // Block theme: anchor variant
            'a[href*="?add-to-cart="]',                         // Catch-all: custom links (Elementor, etc.)
            'a[href*="&add-to-cart="]',                         // Catch-all: custom links with params
        ].join(', ');

        // Handler 1: Click-based — catches ALL add-to-cart clicks.
        // Works on: archive pages (AJAX), single product pages, block themes, page builders.
        // sendBeacon() survives page navigation, so no delay needed.
        // recentAtc dedup prevents double-fire if Handler 2/3/4 also catches the event.
        document.addEventListener('click', function (e) {
            var btn = e.target.closest(atcSelectors);
            if (!btn) return;

            var rawProductId = extractProductId(btn);
            if (!rawProductId) return;

            var productName = '';
            var productPrice = 0;
            var productQty = 1;

            // Scope name/price to nearest .product container (avoids wrong data on multi-product pages).
            var productContainer = btn.closest('.product, .wc-block-grid__product, li.type-product') || document;

            // Read product name (classic selectors + block selectors).
            var nameEl = productContainer.querySelector('.woocommerce-loop-product__title, .wc-block-components-product-name, .product_title, .wp-block-post-title');
            if (nameEl) {
                productName = nameEl.textContent.trim();
            }

            // Read product price — prioritize variation price over base price.
            var priceEl = productContainer.querySelector('.woocommerce-variation-price .woocommerce-Price-amount, .price ins .woocommerce-Price-amount, .price .woocommerce-Price-amount, .wc-block-components-product-price .woocommerce-Price-amount');
            if (priceEl) {
                productPrice = parseFloat(priceEl.textContent.replace(/[^0-9.]/g, '')) || 0;
            }

            // Read quantity from form (single product page).
            var form = btn.closest('form.cart, form.variations_form');
            if (form) {
                var qtyInput = form.querySelector('input[name="quantity"]');
                if (qtyInput && qtyInput.value) {
                    productQty = parseInt(qtyInput.value, 10) || 1;
                }
            }

            fireAddToCartOnce(rawProductId, productName, productPrice, productQty);
        });

        // Handler 2: Classic theme — jQuery AJAX added_to_cart event.
        if (typeof jQuery !== 'undefined') {
            jQuery(document.body).on('added_to_cart', function (evt, fragments, hash, btn) {
                var rawProductId = '';

                if (btn && btn.length) {
                    // Archive pages: button has data-product_id="123".
                    rawProductId = btn.data('product_id') || btn.data('product-id') || '';

                    // Single product fallback: button has name="add-to-cart" value="123".
                    if (!rawProductId && btn.attr('name') === 'add-to-cart' && btn.val()) {
                        rawProductId = btn.val();
                    }

                    // Variable product fallback: form has hidden input name="product_id".
                    if (!rawProductId) {
                        var form = btn.closest('form.cart');
                        if (form.length) {
                            var pidInput = form.find('input[name="product_id"]');
                            if (pidInput.length && pidInput.val()) {
                                rawProductId = pidInput.val();
                            }
                        }
                    }
                }

                if (!rawProductId) return;
                fireAddToCartOnce(String(rawProductId), '', 0);
            });
        }

        // Handler 3: Block theme — WooCommerce Blocks custom event.
        document.body.addEventListener('wc-blocks_added_to_cart', function (evt) {
            var productId = (evt.detail && evt.detail.productId) ? evt.detail.productId : '';
            if (!productId) return;

            fireAddToCartOnce(String(productId), '', 0);
        });

        // Handler 4: Single product page — form.cart submit interceptor.
        // Problem: form POST navigates away, killing fbq() pixel request from Click handler.
        // Solution: intercept submit, check defaultPrevented, delay 300ms, then submit.
        var formSubmitting = false; // Re-entry guard.

        document.addEventListener('submit', function (e) {
            var form = e.target;
            if (!form || !form.classList.contains('cart')) return;

            // Allow the delayed re-submit to pass through.
            if (formSubmitting) return;

            // If WooCommerce validation or an AJAX cart plugin prevented it, respect that.
            if (e.defaultPrevented) return;

            // We must prevent immediate navigation so the fbq() pixel request isn't aborted.
            e.preventDefault();

            // Find the submit button.
            var btn = form.querySelector('.single_add_to_cart_button, button[type="submit"], input[type="submit"]');
            var rawProductId = btn ? extractProductId(btn) : '';

            // Track it now ONLY if Handler 1 (Click) missed it.
            if (rawProductId && !recentAtc[rawProductId]) {
                var productName = '';
                var productPrice = 0;
                var productQty = 1;

                var nameEl = document.querySelector('.product_title, .wp-block-post-title');
                if (nameEl) {
                    productName = nameEl.textContent.trim();
                }

                // Prioritize variation price.
                var priceEl = document.querySelector('.woocommerce-variation-price .woocommerce-Price-amount, .price ins .woocommerce-Price-amount, .price .woocommerce-Price-amount');
                if (priceEl) {
                    productPrice = parseFloat(priceEl.textContent.replace(/[^0-9.]/g, '')) || 0;
                }

                // Read quantity from form.
                var qtyInput = form.querySelector('input[name="quantity"]');
                if (qtyInput && qtyInput.value) {
                    productQty = parseInt(qtyInput.value, 10) || 1;
                }

                fireAddToCartOnce(rawProductId, productName, productPrice, productQty);
            }

            // Always delay form submission 300ms to allow fbq() to send the pixel request.
            formSubmitting = true;
            setTimeout(function () {
                // Use requestSubmit() to preserve WooCommerce validation handlers.
                if (form.requestSubmit && btn && (btn.type === 'submit' || btn.tagName === 'BUTTON')) {
                    form.requestSubmit(btn);
                } else {
                    // Fallback for older browsers (Safari < 14).
                    // form.submit() does NOT include the submit button's name/value.
                    // WooCommerce needs 'add-to-cart=PRODUCT_ID' in POST data.
                    if (btn && rawProductId) {
                        var hiddenInput = document.createElement('input');
                        hiddenInput.type = 'hidden';
                        hiddenInput.name = btn.name || 'add-to-cart';
                        hiddenInput.value = btn.value || rawProductId;
                        form.appendChild(hiddenInput);
                    }
                    form.submit();
                }
                formSubmitting = false;
            }, 300);
        });
    }

    // ── AddPaymentInfo (Checkout — Payment Method Selection) ──
    // Fires ONCE per page load when user selects/changes payment method.
    // Meta Best Practice: "share the same events using both tools" (Pixel + CAPI).
    if (config.eventsConfig && config.eventsConfig.addpaymentinfo !== false) {
        var addPaymentFired = false;

        function handleAddPaymentInfo() {
            if (addPaymentFired) return;

            // Only fire on checkout page (capiflow-page-data with InitiateCheckout = checkout page).
            var pageEl = document.getElementById('capiflow-page-data');
            if (!pageEl) return;
            var pd = null;
            try {
                pd = JSON.parse(pageEl.textContent);
                if (!pd || pd.event !== 'InitiateCheckout') return;
            } catch (e) { return; }

            addPaymentFired = true;

            var selectedMethod = '';
            var checkedRadio = document.querySelector('input[name="payment_method"]:checked, input[name="radio-control-wc-payment-method-options"]:checked');
            if (checkedRadio) {
                selectedMethod = checkedRadio.value || '';
            }

            var cart = (pd && pd.custom_data) ? pd.custom_data : {};

            var eventId = generateEventId();
            fireEvent('AddPaymentInfo', eventId, {
                value: cart.value || 0,
                currency: cart.currency || config.currency || 'BDT',
                content_type: 'product',
                content_ids: cart.content_ids || [],
            });
        }

        // Listen for payment method changes (classic + block checkout).
        document.addEventListener('change', function (e) {
            if (e.target && (
                e.target.name === 'payment_method' ||                                       // Classic checkout
                e.target.name === 'radio-control-wc-payment-method-options' ||               // Block checkout
                (e.target.closest && e.target.closest('.wc-block-components-payment-method-icons')) // Block checkout variant
            )) {
                handleAddPaymentInfo();
            }
        });

        // Also fire on Place Order click (classic + block checkout).
        document.addEventListener('click', function (e) {
            var btn = e.target.closest('#place_order, .wc-block-components-checkout-place-order-button, button.checkout-button');
            if (btn) {
                handleAddPaymentInfo();
            }
        });
    }
    // ── Purchase (Thank You Page — Dedup with Server) ──
    function handlePurchaseDedup() {
        var el = document.getElementById('capiflow-purchase-data');
        if (!el) {
            return;
        }

        try {
            var data = JSON.parse(el.textContent);
            if (!data || data.event !== 'Purchase' || !data.eventId) {
                return;
            }

            // Use the SERVER-generated event_id for perfect dedup.
            if (typeof fbq === 'function') {
                fbq('track', 'Purchase', data.custom_data || {}, { eventID: data.eventId });
            }

            // Do NOT send to proxy — server already handles this.
            // The browser fbq() call + server CAPI call share the same eventID.
        } catch (e) {
            // Silent fail.
        }
    }
    handlePurchaseDedup();

})();
