/*!
 * Seekmodo Search — click beacon
 *
 * Intercepts clicks on elements that carry data-seekmodo-id /
 * data-seekmodo-pos attributes and POSTs the click metadata to the
 * plugin's REST endpoint. Uses navigator.sendBeacon where supported
 * (zero added latency) and falls back to a fetch keepalive ping.
 *
 * Expected DOM contract (auto-injected by SearchSwap on search
 * templates; manual on bespoke themes):
 *
 *   <a href="/some-post/"
 *      data-seekmodo-id="4321"
 *      data-seekmodo-pos="3"
 *      data-seekmodo-surface="serp">...</a>
 *
 * Server side: see src/Events/ClickBeacon.php → POST /wp-json/seekmodo/v1/click.
 */
(function () {
    if (typeof window === 'undefined' || typeof document === 'undefined') {
        return;
    }
    if (!window.SEEKMODO_BEACON || !window.SEEKMODO_BEACON.endpoint) {
        return;
    }

    var ENDPOINT = window.SEEKMODO_BEACON.endpoint;
    var NONCE    = window.SEEKMODO_BEACON.nonce || '';
    function cookieSearchEventId() {
        try {
            var m = document.cookie.match(/(?:^|; )sm_seid=(\d+)/);
            return m ? (parseInt(m[1], 10) || 0) : 0;
        } catch (e) {
            return 0;
        }
    }

    function currentSearchEventId() {
        var fromWindow = parseInt((window.SEEKMODO_BEACON && window.SEEKMODO_BEACON.search_event_id) || '0', 10) || 0;
        return fromWindow || cookieSearchEventId();
    }

    function readKeyword() {
        // 1. Prefer the search input's current value.
        var input = document.querySelector('input[type="search"], input[name="s"]');
        if (input && input.value) {
            return String(input.value).trim();
        }
        // 2. Fall back to the URL ?s= param.
        var p = new URLSearchParams(window.location.search || '');
        return (p.get('s') || '').trim();
    }

    /**
     * Classic WP / Twenty Ten search loops render product hits as
     * `<article id="post-123" class="product …">` with the title
     * anchor outside the WooCommerce loop hooks. Stamp those links
     * client-side so the click listener below can mirror them.
     */
    function stampSearchSerpLinks() {
        if (!readKeyword()) {
            return;
        }
        var pos = 0;

        // WooCommerce product loops (standard + Twenty Ten article.product).
        var productNodes = document.querySelectorAll(
            'article.product[id^="post-"], ul.products li.product.type-product'
        );
        productNodes.forEach(function (el) {
            if (el.classList && el.classList.contains('product-category')) {
                return;
            }
            stampLinkFromContainer(el, ++pos, 'serp');
        });

        // Content vertical SERP (`/?s=…` pages/posts).
        var contentArticles = document.querySelectorAll('article[id^="post-"]:not(.product)');
        contentArticles.forEach(function (el) {
            stampLinkFromContainer(el, ++pos, 'serp');
        });
    }

    function stampLinkFromContainer(el, pos, surface) {
        var idMatch = (el.id || '').match(/^post-(\d+)$/);
        if (!idMatch) {
            idMatch = (el.className || '').match(/\bpost-(\d+)\b/);
        }
        if (!idMatch) {
            return;
        }
        var link = el.querySelector(
            'h2.entry-title > a[href], h3.entry-title > a[href], ' +
            'a.woocommerce-loop-product__link, a.woocommerce-LoopProduct-link'
        );
        if (!link || link.getAttribute('data-seekmodo-id')) {
            return;
        }
        link.setAttribute('data-seekmodo-id', idMatch[1]);
        link.setAttribute('data-seekmodo-pos', String(pos));
        link.setAttribute('data-seekmodo-surface', surface);
        var seid = currentSearchEventId();
        if (seid > 0) {
            link.setAttribute('data-seekmodo-seid', String(seid));
        }
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', stampSearchSerpLinks);
    } else {
        stampSearchSerpLinks();
    }

    function fire(payload) {
        if (!payload || !payload.object_id) {
            return;
        }
        try {
            var body = JSON.stringify(payload);
            // Prefer sendBeacon — fire-and-forget, doesn't block navigation.
            if (navigator.sendBeacon) {
                var blob = new Blob([body], { type: 'application/json' });
                navigator.sendBeacon(ENDPOINT, blob);
                return;
            }
            // Fallback: fetch with keepalive so the request survives
            // the impending navigation.
            fetch(ENDPOINT, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-WP-Nonce': NONCE
                },
                body: body,
                keepalive: true,
                credentials: 'same-origin'
            }).catch(function () { /* swallow */ });
        } catch (e) {
            // Never let an analytics error break navigation.
        }
    }

    function pidFromHref(href) {
        if (!href) {
            return 0;
        }
        var m = href.match(/[?&]products_id=(\d+)/);
        if (m) {
            return parseInt(m[1], 10) || 0;
        }
        m = href.match(/\/(\d+)\/?(?:\?|#|$)/);
        if (m) {
            return parseInt(m[1], 10) || 0;
        }
        m = href.match(/-(\d+)(?:\?|#|\/|$)/);
        return m ? (parseInt(m[1], 10) || 0) : 0;
    }

    function onClick(ev) {
        var target = ev.target;
        // Walk up to a max of 6 ancestors looking for a tagged anchor.
        for (var i = 0; i < 6 && target && target !== document.body; i++) {
            if (target.getAttribute && target.getAttribute('data-seekmodo-id')) {
                var payload = {
                    keyword:   readKeyword(),
                    object_id: parseInt(target.getAttribute('data-seekmodo-id') || '0', 10) || 0,
                    position:  parseInt(target.getAttribute('data-seekmodo-pos') || '1', 10) || 1,
                    surface:   target.getAttribute('data-seekmodo-surface') || 'serp'
                };
                var seidAttr = parseInt(target.getAttribute('data-seekmodo-seid') || '0', 10) || 0;
                var seid = seidAttr || currentSearchEventId();
                // Skip unattributed SERP clicks — they pollute fleet
                // linkage and cannot train LTR.
                if (seid <= 0) {
                    return;
                }
                payload.search_event_id = seid;
                fire(payload);
                return;
            }
            target = target.parentNode;
        }
        var keyword = readKeyword();
        if (!keyword) {
            return;
        }
        var seidFallback = currentSearchEventId();
        if (seidFallback <= 0) {
            return;
        }
        var anchor = ev.target && ev.target.closest
            ? ev.target.closest('a[href]')
            : null;
        if (!anchor || anchor.getAttribute('data-seekmodo-id')) {
            return;
        }
        var objectId = pidFromHref(anchor.href);
        if (!objectId) {
            return;
        }
        fire({
            keyword: keyword,
            object_id: objectId,
            position: 0,
            surface: 'serp',
            search_event_id: seidFallback
        });
    }

    document.addEventListener('click', onClick, true);
})();
