#include "game/analytics.h"
#include <stdio.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>

/* ── EM_JS bridge: JavaScript functions callable from C ─────────── */

/* Initialize client_id in localStorage and store the analytics
 * API URL + key. Called once at startup. */
EM_JS(void, js_analytics_init, (), {
    /* Generate or retrieve a persistent client UUID.
     * crypto.randomUUID() requires a secure context (HTTPS) and is
     * absent in older browsers, so fall back to a manual v4 UUID. */
    if (!localStorage.getItem('jnr_client_id')) {
        var uuid;
        if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
            uuid = crypto.randomUUID();
        } else {
            uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                var r = Math.random() * 16 | 0;
                return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
            });
        }
        localStorage.setItem('jnr_client_id', uuid);
    }
    /* Store config on the Module for later use by other EM_JS calls.
     * ANALYTICS_URL and ANALYTICS_KEY are replaced at build time via
     * -D defines, falling back to sensible defaults. */
    Module._analyticsClientId = localStorage.getItem('jnr_client_id');
    Module._analyticsSessionId = null;
    Module._analyticsStartPending = null; /* Promise while start is in-flight */
    Module._analyticsLastStats = null;    /* stashed for beforeunload fallback */

    /* Runtime config: URL from data attribute, key decoded at runtime.
     * The key is XOR-encoded across two byte arrays so it never appears
     * as a plain string in the WASM binary, emitted JS, or HTML. */
    var container = document.getElementById('canvas-container');
    Module._analyticsUrl = (container && container.dataset.analyticsUrl)
        ? container.dataset.analyticsUrl
        : (typeof ANALYTICS_URL !== 'undefined' ? ANALYTICS_URL : '');
    var _a = [53,75,96,19,114,122,112,34,28,62,24,5,57,34,126,14,
              112,73,105,121,122,79,50,0,77,33,82,58,61,19,44,0];
    var _b = [82,15,4,95,36,32,29,18,95,14,87,95,115,70,12,76,
              55,5,4,12,28,30,65,78,4,72,26,92,84,90,70,54];
    var _k = '';
    for (var i = 0; i < _a.length; i++) _k += String.fromCharCode(_a[i] ^ _b[i]);
    Module._analyticsKey = _k;

    if (!Module._analyticsUrl) {
        console.log('[analytics] No analytics URL configured — analytics disabled');
    } else {
        console.log('[analytics] Initialized, client_id=' + Module._analyticsClientId);
    }
});

/* Start a new session. Sends POST /api/analytics/session/start/.
 * Stores the in-flight promise so session_end can wait for it. */
EM_JS(void, js_analytics_session_start, (), {
    if (!Module._analyticsUrl) return;

    var body = JSON.stringify({
        client_id: Module._analyticsClientId,
        device: {
            platform: navigator.platform || '',
            language: navigator.language || '',
            screen_width: screen.width,
            screen_height: screen.height,
            device_pixel_ratio: window.devicePixelRatio || 1,
            timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || '',
            webgl_renderer: (function() {
                try {
                    var c = document.createElement('canvas');
                    var gl = c.getContext('webgl') || c.getContext('experimental-webgl');
                    if (gl) {
                        var ext = gl.getExtension('WEBGL_debug_renderer_info');
                        return ext ? gl.getParameter(ext.UNMASKED_RENDERER_WEBGL) : '';
                    }
                } catch(e) {}
                return '';
            })(),
            touch_support: ('ontouchstart' in window)
        }
    });

    Module._analyticsStartPending = fetch(Module._analyticsUrl + '/api/analytics/session/start/', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-API-Key': Module._analyticsKey
        },
        body: body
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
        Module._analyticsSessionId = data.session_id || null;
        Module._analyticsStartPending = null;
        console.log('[analytics] Session started: ' + Module._analyticsSessionId);
    })
    .catch(function(err) {
        Module._analyticsStartPending = null;
        console.error('[analytics] Session start failed:', err);
    });
});

/* Internal helper: send the session-end POST (used by both the C wrapper
 * and the beforeunload fallback). */
EM_JS(void, js_analytics_send_end, (int score, int level_reached,
                                     int lives_used, int duration_secs,
                                     const char *end_reason_ptr), {
    /* Helper that performs the actual end request given a session id. */
    function doEnd(sid, endReason, score, levelReached, livesUsed, durationSecs) {
        var body = JSON.stringify({
            score: score,
            level_reached: levelReached > 0 ? levelReached : 1,
            lives_used: livesUsed,
            duration_seconds: durationSecs,
            end_reason: endReason
        });

        /* Stash stats for the beforeunload fallback */
        Module._analyticsLastStats = body;

        return fetch(Module._analyticsUrl + '/api/analytics/session/' + sid + '/end/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-API-Key': Module._analyticsKey
            },
            body: body,
            keepalive: true
        })
        .then(function(r) { return r.json(); })
        .then(function(data) {
            console.log('[analytics] Session ended: ' + sid +
                         (data.new_high_score ? ' (NEW HIGH SCORE!)' : ''));
        })
        .catch(function(err) {
            console.error('[analytics] Session end failed:', err);
        });
    }

    if (!Module._analyticsUrl) return;

    var endReason = UTF8ToString(end_reason_ptr);

    /* If session start is still in-flight, wait for it before ending. */
    if (Module._analyticsStartPending) {
        var pending = Module._analyticsStartPending;
        /* Clear session synchronously so duplicate end calls are harmless */
        Module._analyticsStartPending = null;
        pending.then(function() {
            var sid = Module._analyticsSessionId;
            if (sid) {
                Module._analyticsSessionId = null;
                doEnd(sid, endReason, score, level_reached, lives_used, duration_secs);
            }
        });
        return;
    }

    if (!Module._analyticsSessionId) return;

    var sid = Module._analyticsSessionId;
    /* Clear synchronously before the async request to prevent races */
    Module._analyticsSessionId = null;
    doEnd(sid, endReason, score, level_reached, lives_used, duration_secs);
});

/* ── C wrappers ─────────────────────────────────────────────────── */

void analytics_init(void) {
    js_analytics_init();
}

void analytics_session_start(void) {
    js_analytics_session_start();
}

void analytics_session_end(GameStats *stats, const char *end_reason) {
    stats_update_score(stats);
    js_analytics_send_end(
        stats->score,
        stats->levels_completed > 0 ? stats->levels_completed : 1,
        stats->deaths,
        (int)stats->time_elapsed,
        end_reason
    );
}

#else
/* ── Non-WASM stubs ─────────────────────────────────────────────── */

void analytics_init(void) {
    printf("[analytics] Analytics disabled (native build)\n");
}

void analytics_session_start(void) {}

void analytics_session_end(GameStats *stats, const char *end_reason) {
    (void)stats;
    (void)end_reason;
}

#endif /* __EMSCRIPTEN__ */
