/* Brainwerk SEO Suite frontend beacon — heartbeat + scroll + outbound. ~1.2 KB minified.
 * Loaded only when tracking_mode is 'beacon' or 'hybrid' and the visitor
 * is not excluded server-side. */
(function () {
    'use strict';
    if (!window.seoforge_track || !navigator) return;
    var cfg     = window.seoforge_track;
    var url     = cfg.url;
    var session = cfg.session || '';
    var token   = cfg.token || '';
    var path    = location.pathname || '/';
    var start   = Date.now();
    var lastSent= 0;
    var scroll  = 0;
    var alive   = true;
    var vitals  = { lcp: 0, cls: 0, inp: 0 };

    // Core Web Vitals (field data) via PerformanceObserver. Best-effort: any
    // unsupported entry type is simply skipped. Sent on pagehide.
    try {
        if (window.PerformanceObserver) {
            new PerformanceObserver(function (l) {
                var es = l.getEntries(); var last = es[es.length - 1];
                if (last) vitals.lcp = Math.round(last.startTime);
            }).observe({ type: 'largest-contentful-paint', buffered: true });
            new PerformanceObserver(function (l) {
                l.getEntries().forEach(function (e) { if (!e.hadRecentInput) vitals.cls += e.value; });
            }).observe({ type: 'layout-shift', buffered: true });
            new PerformanceObserver(function (l) {
                l.getEntries().forEach(function (e) { if (e.duration > vitals.inp) vitals.inp = Math.round(e.duration); });
            }).observe({ type: 'event', buffered: true, durationThreshold: 40 });
        }
    } catch (e) {}

    function send(payload, useBeacon) {
        try {
            payload.session = session;
            payload.path    = path;
            payload.token   = token;
            var body = JSON.stringify(payload);
            if (useBeacon && navigator.sendBeacon) {
                navigator.sendBeacon(url, new Blob([body], { type: 'application/json' }));
            } else {
                fetch(url, {
                    method: 'POST',
                    keepalive: true,
                    headers: { 'Content-Type': 'application/json' },
                    body: body,
                    credentials: 'same-origin'
                }).catch(function () {});
            }
        } catch (e) {}
    }

    function duration() {
        return Math.round((Date.now() - start) / 1000);
    }

    function trackScroll() {
        var doc = document.documentElement;
        var max = (doc.scrollHeight - doc.clientHeight);
        if (max <= 0) return;
        var pct = Math.min(100, Math.round((window.scrollY / max) * 100));
        if (pct > scroll) scroll = pct;
    }

    function heartbeat() {
        if (!alive) return;
        var d = duration();
        if (d - lastSent < 10) return; // never more than once / 10s
        lastSent = d;
        send({ event: 'heartbeat', duration: d, scroll: scroll }, false);
    }

    function exit() {
        if (!alive) return;
        alive = false;
        send({
            event: 'pagehide',
            duration: duration(),
            scroll: scroll,
            lcp: vitals.lcp,
            cls: Math.round(vitals.cls * 1000) / 1000,
            inp: vitals.inp
        }, true);
    }

    // Outbound link clicks.
    document.addEventListener('click', function (e) {
        var t = e.target;
        while (t && t.tagName !== 'A') t = t.parentNode;
        if (!t || !t.href) return;
        if (t.host && t.host !== location.host && t.host !== '') {
            send({ event: 'outbound', outbound: t.href }, true);
        }
    }, true);

    // Heartbeat every 15s.
    var hbTimer = setInterval(heartbeat, 15000);

    // SPA pushState — when route changes, finalize the old page and start new.
    var pushState = history.pushState;
    history.pushState = function () {
        send({ event: 'spa_exit', duration: duration(), scroll: scroll }, false);
        var r = pushState.apply(this, arguments);
        path  = location.pathname || '/';
        start = Date.now();
        lastSent = 0;
        scroll = 0;
        return r;
    };
    window.addEventListener('popstate', function () {
        send({ event: 'spa_exit', duration: duration(), scroll: scroll }, false);
        path  = location.pathname || '/';
        start = Date.now();
        scroll = 0;
    });

    window.addEventListener('scroll', trackScroll, { passive: true });
    window.addEventListener('pagehide', exit);
    document.addEventListener('visibilitychange', function () {
        if (document.visibilityState === 'hidden') heartbeat();
    });
})();
