// statsig_shim.js — browser-environment shim that lets grok.com's own obfuscated
// x-statsig-id signer run inside goja. grok's code does all the (per-build,
// rotating) byte-indexing/curve-selection; we only provide the STABLE browser
// primitives it reads from: the seed <meta>, the .r-aufz1o SVG curve DOM, and a
// standard Web-Animations getComputedStyle sampler. Inputs arrive via globals set
// by Go before each sign: __SEED (base64 str), __CURVES (JSON [[{color,deg,bezier}]]),
// __PATH, __METHOD. Go also injects __goSha256(Uint8Array)->ArrayBuffer.
(function () {
  'use strict';
  var g = globalThis;

  // ---- base64 (goja has no atob/btoa) ----
  var B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  g.atob = function (s) {
    s = String(s).replace(/=+$/, '');
    var out = '', bits = 0, val = 0;
    for (var i = 0; i < s.length; i++) {
      var c = B64.indexOf(s.charAt(i));
      if (c < 0) continue;
      val = (val << 6) | c; bits += 6;
      if (bits >= 8) { bits -= 8; out += String.fromCharCode((val >> bits) & 0xff); }
    }
    return out;
  };
  g.btoa = function (s) {
    s = String(s); var out = '';
    for (var i = 0; i < s.length; i += 3) {
      var b0 = s.charCodeAt(i), b1 = s.charCodeAt(i + 1), b2 = s.charCodeAt(i + 2);
      var h0 = b0 >> 2, h1 = ((b0 & 3) << 4) | (b1 >> 4);
      var h2 = ((b1 & 15) << 2) | (b2 >> 6), h3 = b2 & 63;
      out += B64[h0] + B64[h1];
      out += isNaN(b1) ? '=' : B64[h2];
      out += isNaN(b2) ? '=' : B64[h3];
    }
    return out;
  };

  // ---- TextEncoder (goja has no TextEncoder) ----
  if (typeof g.TextEncoder === 'undefined') {
    g.TextEncoder = function () {};
    g.TextEncoder.prototype.encode = function (str) {
      str = String(str);
      var bytes = [];
      for (var i = 0; i < str.length; i++) {
        var c = str.charCodeAt(i);
        if (c < 0x80) bytes.push(c);
        else if (c < 0x800) { bytes.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f)); }
        else if (c >= 0xd800 && c <= 0xdbff) { // surrogate pair
          var c2 = str.charCodeAt(++i);
          var cp = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff);
          bytes.push(0xf0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3f), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
        } else { bytes.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); }
      }
      return Uint8Array.from(bytes);
    };
  }

  // ---- crypto.subtle.digest, backed by Go SHA-256 ----
  g.crypto = g.crypto || {};
  g.crypto.subtle = g.crypto.subtle || {};
  g.crypto.subtle.digest = function (algo, data) {
    // grok only ever asks for sha-256; g.__goSha256 returns an ArrayBuffer
    var bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
    return Promise.resolve(g.__goSha256(bytes));
  };

  // ---- Web Animations getComputedStyle sampler (the only real math we own) ----
  var K = 4096;
  function cubicBezier(x1, y1, x2, y2, p) {
    if (p <= 0) return 0; if (p >= 1) return 1;
    function bez(t, a, b) { var mt = 1 - t; return 3 * a * mt * mt * t + 3 * b * mt * t * t + t * t * t; }
    var lo = 0, hi = 1;
    for (var i = 0; i < 100; i++) { var m = (lo + hi) / 2; if (bez(m, x1, x2) < p) lo = m; else hi = m; }
    return bez((lo + hi) / 2, y1, y2);
  }
  function hexToRgb(h) { h = h.replace('#', ''); return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)]; }
  function sample(anim) {
    var kf = anim.keyframes, dur = anim.duration || K;
    var frac = anim.currentTime / dur; if (frac < 0) frac = 0; if (frac > 1) frac = 1;
    var bm = /cubic-bezier\(([^)]+)\)/.exec(kf.easing || '');
    var eased = frac;
    if (bm) { var p = bm[1].split(',').map(Number); eased = cubicBezier(p[0], p[1], p[2], p[3], frac); }
    var c0 = hexToRgb(kf.color[0]), c1 = hexToRgb(kf.color[1]);
    var col = [0, 1, 2].map(function (i) { return Math.round(c0[i] + (c1[i] - c0[i]) * eased); });
    var d0 = parseFloat(/rotate\(([-\d.]+)deg\)/.exec(kf.transform[0])[1]);
    var d1 = parseFloat(/rotate\(([-\d.]+)deg\)/.exec(kf.transform[1])[1]);
    var ang = (d0 + (d1 - d0) * eased) * Math.PI / 180;
    var cos = Math.cos(ang), sin = Math.sin(ang);
    return { color: 'rgb(' + col[0] + ', ' + col[1] + ', ' + col[2] + ')',
             transform: 'matrix(' + cos + ', ' + sin + ', ' + (-sin) + ', ' + cos + ', 0, 0)' };
  }

  // ---- minimal DOM ----
  function makeEl(props) {
    var e = {
      nodeName: 'DIV', style: {}, childNodes: [], attrs: {}, _anim: null, _parent: null,
      setAttribute: function (k, v) { e.attrs[k] = v; },
      getAttribute: function (k) { return (k in e.attrs) ? e.attrs[k] : (props && props.attrs && k in props.attrs ? props.attrs[k] : null); },
      appendChild: function (c) { e.childNodes.push(c); return c; },
      append: function (c) { e.childNodes.push(c); return c; },
      removeChild: function (c) { return c; },
      remove: function () {},
      animate: function (keyframes, opts) {
        var anim = {
          keyframes: keyframes,
          duration: (opts && opts.duration) || (typeof opts === 'number' ? opts : K),
          currentTime: 0, pause: function () {}, play: function () {}, cancel: function () {},
          effect: { getKeyframes: function () { return Array.isArray(keyframes) ? keyframes : [keyframes]; } },
        };
        e._anim = anim; return anim;
      },
      getAnimations: function () { return e._anim ? [e._anim] : []; },
    };
    if (props) for (var k in props) if (k !== 'attrs') e[k] = props[k];
    Object.defineProperty(e, 'parentElement', { get: function () { return e._parent; } });
    Object.defineProperty(e, 'innerHTML', { set: function (v) { e._html = v; }, get: function () { return e._html; } });
    Object.defineProperty(e, 'textContent', { set: function (v) { e._text = v; }, get: function () { return e._text; } });
    return e;
  }

  // .r-aufz1o group: g.childNodes[0].childNodes[1].getAttribute('d') = svg path whose
  // numbers (after substring(9), split('C')) decode back to each curve [c0..c5,deg,b0..b3].
  function groupEl(flatCurves) {
    var d = '_________' + flatCurves.map(function (c) { return c.join(' '); }).join('C');
    var path = makeEl({ attrs: { d: d } });
    var inner = makeEl(); inner.childNodes = [makeEl(), path];
    var outer = makeEl(); outer.childNodes = [inner]; outer._parent = makeEl();
    return outer;
  }

  var docBody = makeEl();
  g.document = {
    currentScript: null, body: docBody, head: makeEl(),
    createElement: function (tag) { return makeEl({ nodeName: String(tag || 'div').toUpperCase() }); },
    querySelectorAll: function (sel) {
      sel = String(sel);
      // The seed <meta> is selected by a name/verification attribute selector
      // (e.g. [name^=gr] or [name*=verification]); the curve group container is
      // selected by a per-build hashed CLASS selector (e.g. .r-aufz1o, .r-3nqkqc)
      // which rotates on every reship — so match by shape, not literal class.
      if (/verification|name/i.test(sel)) {
        var seed = g.__SEED;
        return [{ nodeName: 'META', getAttribute: function (a) { return a === 'content' ? seed : null; },
                  get content() { return seed; } }];
      }
      if (/(^|\s|,)\./.test(sel)) {
        var curves = JSON.parse(g.__CURVES);
        return curves.map(function (grp) {
          return groupEl(grp.map(function (cv) { return cv.color.concat([cv.deg], cv.bezier); }));
        });
      }
      return [];
    },
    querySelector: function (sel) { var r = this.querySelectorAll(sel); return r[0] || null; },
  };
  g.window = g;
  g.self = g;
  g.getComputedStyle = function (el) { return el && el._anim ? sample(el._anim) : { color: 'rgb(0, 0, 0)', transform: 'none' }; };
  g.navigator = g.navigator || { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36' };
  g.location = g.location || { href: 'https://grok.com/', origin: 'https://grok.com', pathname: '/' };

  // ---- Turbopack capture + bootstrap ----
  var TP = []; TP.push = function (entry) { TP._entry = entry; return 0; };
  g.TURBOPACK = TP;

  // Called by Go AFTER the signer chunk is eval'd: run the module factory, grab default.
  g.__grokBootstrap = function () {
    var entry = TP._entry;
    if (!entry) throw new Error('turbopack entry not registered');
    var factory = entry[2];
    var exports = {};
    var ctx = {
      s: function () {
        var flat = Array.prototype.slice.call(arguments).flat(Infinity);
        var name = null;
        for (var i = 0; i < flat.length; i++) {
          var x = flat[i];
          if (typeof x === 'string') name = x;
          else if (typeof x === 'function' && name != null) {
            (function (nm, getter) { Object.defineProperty(exports, nm, { get: getter, configurable: true, enumerable: true }); })(name, x);
            name = null;
          }
        }
      },
    };
    factory(ctx);
    // exports.default is a GETTER that invokes the module factory on every read,
    // returning a FRESH async signer (path,method)=>Promise<id> with a fresh internal
    // curve cache. Keep the exports object; read .default fresh per sign so different
    // sessions' curves never leak through the closure cache.
    g.__grokExports = exports;
    if (typeof exports.default !== 'function') throw new Error('no default export');
  };

  // Called by Go per sign. Fresh signer each time via the re-invoking getter.
  g.__grokSign = function () {
    var signer = g.__grokExports.default; // fresh async signer
    return signer(g.__PATH, g.__METHOD);  // returns Promise<string>
  };

  // Synchronous bridge: Go calls this via RunString (which drains goja's job queue),
  // then reads __grokResult / __grokErr. Works because crypto.subtle.digest resolves
  // synchronously (Promise.resolve over a Go SHA-256), so the whole await chain settles
  // within the microtask drain.
  g.__grokResult = null;
  g.__grokErr = null;
  g.__grokSignInto = function () {
    g.__grokResult = null; g.__grokErr = null;
    try {
      g.__grokSign().then(
        function (r) { g.__grokResult = r; },
        function (e) { g.__grokErr = (e && e.stack) ? String(e.stack) : String(e); }
      );
    } catch (e) { g.__grokErr = (e && e.stack) ? String(e.stack) : String(e); }
  };
})();
