// 浏览器端 Node.js 内置模块 polyfill
// 用于加载 webpack/ncc 打包的官方音源插件
// 提供 http/https (基于 fetch)、stream、util、events、crypto、url、zlib、path、fs、buffer 等

function createEventEmitter(): any {
  const listeners: Record<string, Function[]> = {};
  const self: any = {
    on(event: string, fn: Function) {
      (listeners[event] = listeners[event] || []).push(fn);
      return self;
    },
    once(event: string, fn: Function) {
      const wrapper = (...args: any[]) => {
        self.off(event, wrapper);
        fn(...args);
      };
      return self.on(event, wrapper);
    },
    off(event: string, fn: Function) {
      if (listeners[event]) {
        listeners[event] = listeners[event].filter((f: Function) => f !== fn);
      }
      return self;
    },
    emit(event: string, ...args: any[]) {
      const fns = listeners[event] || [];
      for (const fn of fns) {
        try { fn.apply(null, args); } catch (_) {}
      }
      return true;
    },
    addListener: function() { return self.on.apply(self, arguments as any); },
    removeListener: function() { return self.off.apply(self, arguments as any); },
    removeAllListeners(event?: string) {
      if (event) delete listeners[event];
      else { for (const k in listeners) delete listeners[k]; }
      return self;
    },
    listeners(event: string) { return listeners[event] || []; },
  };
  return self;
}

function createStreamBase(): any {
  function Stream() {}
  Stream.prototype.pipe = function(dest: any) { return dest; };
  Stream.prototype.on = function(_e: string, _fn: Function) { return this; };
  Stream.prototype.emit = function() { return true; };
  return Stream;
}

function createReadable(): any {
  function Readable() {}
  Readable.prototype.pipe = function(dest: any) { return dest; };
  Readable.prototype.on = function() { return this; };
  Readable.prototype.once = function() { return this; };
  Readable.prototype.emit = function() { return true; };
  Readable.prototype.read = function() { return null; };
  Readable.prototype.pause = function() { return this; };
  Readable.prototype.resume = function() { return this; };
  Readable.prototype.push = function() { return this; };
  return Readable;
}

function createWritable(): any {
  function Writable() {}
  Writable.prototype.write = function() { return true; };
  Writable.prototype.end = function() { return this; };
  Writable.prototype.on = function() { return this; };
  Writable.prototype.once = function() { return this; };
  Writable.prototype.emit = function() { return true; };
  return Writable;
}

function createTransform(): any {
  function Transform() {}
  Transform.prototype.pipe = function(dest: any) { return dest; };
  Transform.prototype.write = function() { return true; };
  Transform.prototype.end = function() { return this; };
  Transform.prototype.on = function() { return this; };
  Transform.prototype.once = function() { return this; };
  Transform.prototype.emit = function() { return true; };
  return Transform;
}

function createPassThrough(): any {
  function PassThrough() {}
  PassThrough.prototype.pipe = function(dest: any) { return dest; };
  PassThrough.prototype.write = function() { return true; };
  PassThrough.prototype.end = function() { return this; };
  PassThrough.prototype.on = function() { return this; };
  PassThrough.prototype.once = function() { return this; };
  PassThrough.prototype.emit = function() { return true; };
  return PassThrough;
}

function parseUrl(u: string): any {
  try {
    const url = new URL(u, typeof window !== 'undefined' ? window.location.href : 'http://localhost/');
    return {
      protocol: url.protocol,
      hostname: url.hostname,
      host: url.host,
      port: url.port || (url.protocol === 'https:' ? '443' : '80'),
      pathname: url.pathname,
      path: url.pathname + url.search,
      search: url.search,
      query: Object.fromEntries(url.searchParams.entries()),
      hash: url.hash,
      href: url.href,
      auth: url.username ? url.username + (url.password ? ':' + url.password : '') : '',
    };
  } catch {
    return { protocol: '', hostname: '', host: '', pathname: '', path: '', href: u, port: '80' };
  }
}

// http/https 模块 - 用 fetch 实现
function createHttpModule(isHttps: boolean): any {
  function request(options: any, callback?: (res: any) => void): any {
    let url: string;
    let opts: any = typeof options === 'string' ? {} : { ...options };
    if (typeof options === 'string') {
      url = options;
    } else if (options && typeof options === 'object') {
      const protocol = opts.protocol || (isHttps ? 'https:' : 'http:');
      const host = opts.hostname || opts.host || 'localhost';
      const port = opts.port ? ':' + opts.port : '';
      const path = opts.path || opts.pathname || '/';
      url = protocol + '//' + host + port + path;
    } else {
      url = String(options);
    }

    const method = opts.method || 'GET';
    const headers = opts.headers || {};

    const req: any = createEventEmitter();
    let requestBodyChunks: Uint8Array[] = [];
    let ended = false;

    req.write = function(chunk: any) {
      if (chunk) requestBodyChunks.push(typeof chunk === 'string' ? new TextEncoder().encode(chunk) : chunk);
      return true;
    };
    req.end = function(chunk: any) {
      if (chunk) req.write(chunk);
      if (ended) return;
      ended = true;

      let body: any = undefined;
      if (method !== 'GET' && method !== 'HEAD' && requestBodyChunks.length > 0) {
        if (requestBodyChunks.length === 1) body = requestBodyChunks[0];
        else {
          const total = requestBodyChunks.reduce((a, b) => a + b.length, 0);
          const merged = new Uint8Array(total);
          let offset = 0;
          for (const c of requestBodyChunks) { merged.set(c, offset); offset += c.length; }
          body = merged;
        }
      }

      fetch(url, {
        method,
        headers,
        body,
        signal: opts.signal,
        mode: 'cors',
        credentials: 'omit',
      } as any).then((resp: any) => {
        const res: any = createEventEmitter();
        res.statusCode = resp.status;
        res.statusMessage = resp.statusText;
        res.headers = {};
        try {
          resp.headers.forEach((v: string, k: string) => { res.headers[k.toLowerCase()] = v; });
        } catch {}
        res.setEncoding = function() { return res; };
        res.pipe = function(dest: any) {
          resp.arrayBuffer().then((buf: ArrayBuffer) => {
            if (dest && typeof dest.write === 'function') dest.write(new Uint8Array(buf));
            if (dest && typeof dest.end === 'function') dest.end();
            res.emit('end');
          }).catch((err: Error) => res.emit('error', err));
          return dest;
        };
        res.text = () => resp.text();
        res.json = () => resp.json();
        res.body = resp.body;
        if (callback) callback(res);
        req.emit('response', res);

        // 如果没有 callback，等待 body 然后发射 data/end 事件
        if (!callback) {
          resp.arrayBuffer().then((buf: ArrayBuffer) => {
            res.emit('data', new Uint8Array(buf));
            res.emit('end');
          }).catch((err: Error) => res.emit('error', err));
        }
      }).catch((err: Error) => {
        req.emit('error', err);
      });
      return req;
    };
    req.abort = function() { req.emit('abort'); };
    req.setTimeout = function() { return req; };
    req.setHeader = function(name: string, value: string) { (headers as any)[name.toLowerCase()] = value; return req; };
    req.getHeader = function(name: string) { return (headers as any)[name.toLowerCase()]; };
    req.removeHeader = function(name: string) { delete (headers as any)[name.toLowerCase()]; };

    // 如果用户立即调用 req.end()，我们需要在 next tick 开始 - 但实际上用户必须自己调用 end
    return req;
  }

  function get(options: any, callback?: (res: any) => void): any {
    const req = request(options, callback);
    req.end();
    return req;
  }

  return {
    request,
    get,
    createServer: () => ({ listen: () => {}, close: () => {} }),
    Agent: function() { this.maxSockets = 50; },
    globalAgent: { maxSockets: 50 },
    STATUS_CODES: {},
  };
}

// util 模块
const utilModule: any = {
  inspect: (obj: any) => {
    try { return JSON.stringify(obj); } catch { return String(obj); }
  },
  format: function() { return Array.prototype.slice.call(arguments).join(' '); },
  inherits: function(ctor: any, superCtor: any) {
    if (!superCtor || !superCtor.prototype) return;
    ctor.super_ = superCtor;
    const origProto = ctor.prototype;
    ctor.prototype = Object.create(superCtor.prototype, {
      constructor: { value: ctor, enumerable: false, writable: true, configurable: true },
    });
    // 保留原型上原有的属性
    if (origProto) {
      for (const k in origProto) {
        if (Object.prototype.hasOwnProperty.call(origProto, k)) {
          ctor.prototype[k] = origProto[k];
        }
      }
    }
  },
  promisify: function(fn: any) {
    return function() {
      const args = Array.prototype.slice.call(arguments);
      return new Promise((resolve, reject) => {
        args.push((err: any, ...rest: any[]) => {
          if (err) reject(err);
          else resolve(rest.length === 1 ? rest[0] : rest);
        });
        try { fn.apply(null, args); } catch (e) { reject(e); }
      });
    };
  },
  callbackify: function(fn: any) {
    return function() {
      const args = Array.prototype.slice.call(arguments);
      const cb = args.pop();
      fn.apply(null, args).then((r: any) => cb(null, r)).catch((e: Error) => cb(e));
    };
  },
  TextDecoder: typeof (globalThis as any).TextDecoder !== 'undefined' ? (globalThis as any).TextDecoder : function(this: any) { this.decode = function() { return ''; }; },
  TextEncoder: typeof (globalThis as any).TextEncoder !== 'undefined' ? (globalThis as any).TextEncoder : function(this: any) { this.encode = function(s: string) { return s; }; },
  types: { isDate: (x: any) => x instanceof Date, isRegExp: (x: any) => x instanceof RegExp, isError: (x: any) => x instanceof Error, isArray: Array.isArray, isFunction: (x: any) => typeof x === 'function' },
};

function simpleHash(algo: string, data: Uint8Array): Uint8Array {
  let s = '';
  for (let i = 0; i < data.length; i++) s += String.fromCharCode(data[i]);
  const algoKey = algo.toLowerCase();
  if (algoKey === 'md5') {
    let a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476;
    const msg = new Uint8Array(data.length + 1);
    msg.set(data);
    const bitLen = data.length * 8;
    msg[data.length] = 0x80;
    const paddedLen = (((data.length + 9 + 63) & ~63) + 64) * 4;
    const padded = new Uint8Array(paddedLen);
    padded.set(msg);
    const view = new DataView(padded.buffer);
    view.setUint32(paddedLen - 8, bitLen >>> 32, true);
    view.setUint32(paddedLen - 4, bitLen & 0xffffffff, true);
    for (let i = 0; i < paddedLen; i += 64) {
      const w = new Uint32Array(80);
      for (let j = 0; j < 16; j++) w[j] = view.getUint32(i + j * 4, true);
      for (let j = 16; j < 80; j++) {
        w[j] = (w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]);
        w[j] = (w[j] << 1) | (w[j] >>> 31);
      }
      let A = a, B = b, C = c, D = d;
      for (let j = 0; j < 80; j++) {
        let F: number, g: number;
        if (j < 20) { F = (B & C) | (~B & D); g = 0x5a827999; }
        else if (j < 40) { F = B ^ C ^ D; g = 0x6ed9eba1; }
        else if (j < 60) { F = (B & C) | (B & D) | (C & D); g = 0x8f1bbcdc; }
        else { F = B ^ C ^ D; g = 0xca62c1d6; }
        const temp = ((A << 5) | (A >>> 27)) + F + w[j] + g;
        D = C; C = B; B = (B << 30) | (B >>> 2); A = temp;
      }
      a += A; b += B; c += C; d += D;
    }
    const out = new Uint8Array(16);
    const v = new DataView(out.buffer);
    v.setUint32(0, a, true); v.setUint32(4, b, true);
    v.setUint32(8, c, true); v.setUint32(12, d, true);
    return out;
  }
  let hash = 0;
  for (let i = 0; i < s.length; i++) hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0;
  const hex = Math.abs(hash).toString(16).padStart(8, '0');
  const out = new Uint8Array(8);
  for (let i = 0; i < 8; i++) out[i] = parseInt(hex.substr(i*2, 2), 16);
  return out;
}

function toBuffer(data: any): Uint8Array {
  if (data instanceof Uint8Array) return data;
  if (typeof data === 'string') return new TextEncoder().encode(data);
  if (Array.isArray(data)) return new Uint8Array(data);
  if (data?.buffer instanceof ArrayBuffer) return new Uint8Array(data.buffer);
  return new Uint8Array(0);
}

function bufferToString(buf: Uint8Array, encoding?: string): string {
  if (encoding === 'hex') {
    let s = '';
    for (let i = 0; i < buf.length; i++) s += buf[i].toString(16).padStart(2, '0');
    return s;
  }
  if (encoding === 'base64') {
    let s = '';
    for (let i = 0; i < buf.length; i++) s += String.fromCharCode(buf[i]);
    try { return btoa(s); } catch { return s; }
  }
  return new TextDecoder().decode(buf);
}

// Minimal AES-128-ECB implementation (pure JS, for environments where Web Crypto ECB is unavailable)
function aesEcbEncrypt(data: Uint8Array, key: Uint8Array): Uint8Array {
  if (key.length !== 16) throw new Error('AES-128 key must be 16 bytes');
  const Nb = 4, Nk = 4, Nr = 10;
  const sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16];
  const rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
  const w = new Uint8Array(Nb * (Nr + 1) * 4);
  for (let i = 0; i < Nk; i++) { w[i*4] = key[i*4]; w[i*4+1] = key[i*4+1]; w[i*4+2] = key[i*4+2]; w[i*4+3] = key[i*4+3]; }
  for (let i = Nk; i < Nb * (Nr + 1); i++) {
    let temp = [w[(i-1)*4], w[(i-1)*4+1], w[(i-1)*4+2], w[(i-1)*4+3]];
    if (i % Nk === 0) {
      const t = temp[0]; temp[0] = sbox[temp[1]] ^ rcon[i/Nk - 1]; temp[1] = sbox[temp[2]]; temp[2] = sbox[temp[3]]; temp[3] = sbox[t];
    }
    w[i*4] = w[(i-Nk)*4] ^ temp[0]; w[i*4+1] = w[(i-Nk)*4+1] ^ temp[1]; w[i*4+2] = w[(i-Nk)*4+2] ^ temp[2]; w[i*4+3] = w[(i-Nk)*4+3] ^ temp[3];
  }
  function addRoundKey(state: Uint8Array, round: number) { for (let i = 0; i < 16; i++) state[i] ^= w[round * 16 + i]; }
  function subBytes(state: Uint8Array) { for (let i = 0; i < 16; i++) state[i] = sbox[state[i]]; }
  function shiftRows(state: Uint8Array) {
    const t = state[1]; state[1] = state[5]; state[5] = state[9]; state[9] = state[13]; state[13] = t;
    const t2 = state[2]; state[2] = state[10]; state[10] = t2;
    const t3 = state[6]; state[6] = state[14]; state[14] = t3;
    const t4 = state[15]; state[15] = state[11]; state[11] = state[7]; state[7] = state[3]; state[3] = t4;
  }
  function mixColumns(state: Uint8Array) {
    for (let c = 0; c < 4; c++) {
      const i = c * 4;
      const a = [state[i], state[i+1], state[i+2], state[i+3]];
      state[i] = gmul(2, a[0]) ^ gmul(3, a[1]) ^ a[2] ^ a[3];
      state[i+1] = a[0] ^ gmul(2, a[1]) ^ gmul(3, a[2]) ^ a[3];
      state[i+2] = a[0] ^ a[1] ^ gmul(2, a[2]) ^ gmul(3, a[3]);
      state[i+3] = gmul(3, a[0]) ^ a[1] ^ a[2] ^ gmul(2, a[3]);
    }
  }
  function gmul(a: number, b: number): number {
    let p = 0;
    for (let i = 0; i < 8; i++) {
      if (b & 1) p ^= a;
      const hi = a & 0x80;
      a = (a << 1) & 0xff;
      if (hi) a ^= 0x1b;
      b >>= 1;
    }
    return p;
  }
  const padded = data.length % 16 === 0 ? new Uint8Array(data) : (() => { const p = 16 - (data.length % 16); const out = new Uint8Array(data.length + p); out.set(data); for (let i = 0; i < p; i++) out[data.length + i] = p; return out; })();
  const blocks = padded.length / 16;
  const out = new Uint8Array(padded.length);
  for (let b = 0; b < blocks; b++) {
    const state = new Uint8Array(padded.subarray(b * 16, (b + 1) * 16));
    addRoundKey(state, 0);
    for (let round = 1; round <= Nr; round++) {
      subBytes(state);
      shiftRows(state);
      if (round < Nr) mixColumns(state);
      addRoundKey(state, round);
    }
    out.set(state, b * 16);
  }
  if (data.length % 16 !== 0) return out.subarray(0, data.length);
  return out;
}

function aesEcbDecrypt(data: Uint8Array, key: Uint8Array): Uint8Array {
  if (key.length !== 16) throw new Error('AES-128 key must be 16 bytes');
  const Nb = 4, Nk = 4, Nr = 10;
  const sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16];
  const invSbox = new Uint8Array(256);
  for (let i = 0; i < 256; i++) invSbox[sbox[i]] = i;
  const rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
  const w = new Uint8Array(Nb * (Nr + 1) * 4);
  for (let i = 0; i < Nk; i++) { w[i*4] = key[i*4]; w[i*4+1] = key[i*4+1]; w[i*4+2] = key[i*4+2]; w[i*4+3] = key[i*4+3]; }
  for (let i = Nk; i < Nb * (Nr + 1); i++) {
    let temp = [w[(i-1)*4], w[(i-1)*4+1], w[(i-1)*4+2], w[(i-1)*4+3]];
    if (i % Nk === 0) { const t = temp[0]; temp[0] = sbox[temp[1]] ^ rcon[i/Nk - 1]; temp[1] = sbox[temp[2]]; temp[2] = sbox[temp[3]]; temp[3] = sbox[t]; }
    w[i*4] = w[(i-Nk)*4] ^ temp[0]; w[i*4+1] = w[(i-Nk)*4+1] ^ temp[1]; w[i*4+2] = w[(i-Nk)*4+2] ^ temp[2]; w[i*4+3] = w[(i-Nk)*4+3] ^ temp[3];
  }
  function addRoundKey(state: Uint8Array, round: number) { for (let i = 0; i < 16; i++) state[i] ^= w[round * 16 + i]; }
  function invSubBytes(state: Uint8Array) { for (let i = 0; i < 16; i++) state[i] = invSbox[state[i]]; }
  function invShiftRows(state: Uint8Array) {
    const t = state[13]; state[13] = state[9]; state[9] = state[5]; state[5] = state[1]; state[1] = t;
    const t2 = state[2]; state[2] = state[10]; state[10] = t2;
    const t3 = state[14]; state[14] = state[6]; state[6] = t3;
    const t4 = state[3]; state[3] = state[7]; state[7] = state[11]; state[11] = state[15]; state[15] = t4;
  }
  function invMixColumns(state: Uint8Array) {
    for (let c = 0; c < 4; c++) {
      const i = c * 4;
      const a = [state[i], state[i+1], state[i+2], state[i+3]];
      state[i] = gmul(14, a[0]) ^ gmul(11, a[1]) ^ gmul(13, a[2]) ^ gmul(9, a[3]);
      state[i+1] = gmul(9, a[0]) ^ gmul(14, a[1]) ^ gmul(11, a[2]) ^ gmul(13, a[3]);
      state[i+2] = gmul(13, a[0]) ^ gmul(9, a[1]) ^ gmul(14, a[2]) ^ gmul(11, a[3]);
      state[i+3] = gmul(11, a[0]) ^ gmul(13, a[1]) ^ gmul(9, a[2]) ^ gmul(14, a[3]);
    }
  }
  function gmul(a: number, b: number): number {
    let p = 0;
    for (let i = 0; i < 8; i++) {
      if (b & 1) p ^= a;
      const hi = a & 0x80;
      a = (a << 1) & 0xff;
      if (hi) a ^= 0x1b;
      b >>= 1;
    }
    return p;
  }
  if (data.length % 16 !== 0) throw new Error('AES data must be multiple of 16 bytes');
  const blocks = data.length / 16;
  const out = new Uint8Array(data.length);
  for (let b = 0; b < blocks; b++) {
    const state = new Uint8Array(data.subarray(b * 16, (b + 1) * 16));
    addRoundKey(state, Nr);
    for (let round = Nr - 1; round >= 0; round--) {
      invShiftRows(state);
      invSubBytes(state);
      addRoundKey(state, round);
      if (round > 0) invMixColumns(state);
    }
    out.set(state, b * 16);
  }
  return out;
}

function rsaPublicEncrypt(data: Uint8Array, keyPem: string): Uint8Array {
  const pemHeader = '-----BEGIN PUBLIC KEY-----';
  const pemFooter = '-----END PUBLIC KEY-----';
  let pemData = keyPem.substring(pemHeader.length);
  pemData = pemData.substring(0, pemData.indexOf(pemFooter)).trim();
  const der = Uint8Array.from(atob(pemData), c => c.charCodeAt(0));
  // Parse RSA public key from DER (simple PKCS#1 / SubjectPublicKeyInfo)
  let offset = 0;
  function readLen(): number {
    const b = der[offset++];
    if (b < 0x80) return b;
    const n = b & 0x7f;
    let len = 0;
    for (let i = 0; i < n; i++) len = (len << 8) | der[offset++];
    return len;
  }
  function readTag(tag: number): Uint8Array {
    if (der[offset++] !== tag) throw new Error('Invalid DER tag');
    const len = readLen();
    const buf = der.subarray(offset, offset + len);
    offset += len;
    return buf;
  }
  offset = 0;
  if (der[offset++] !== 0x30) throw new Error('Invalid DER sequence');
  readLen();
  if (der[offset] === 0x30) {
    readTag(0x30);
    readTag(0x06);
    offset++; readLen();
    if (der[offset++] !== 0x03) throw new Error('Invalid DER bit string');
    readLen();
    offset++;
    if (der[offset++] !== 0x00) throw new Error('Invalid DER padding');
    if (der[offset++] !== 0x30) throw new Error('Invalid DER inner sequence');
    readLen();
  }
  const nDer = readTag(0x02);
  const eDer = readTag(0x02);
  function bigFromBytes(bytes: Uint8Array): bigint {
    let hex = '';
    for (const b of bytes) hex += b.toString(16).padStart(2, '0');
    return BigInt('0x' + hex);
  }
  const n = bigFromBytes(nDer);
  const e = bigFromBytes(eDer);
  const dataInt = bigFromBytes(data);
  const result = dataInt ** e % n;
  let hex = result.toString(16);
  if (hex.length % 2 === 1) hex = '0' + hex;
  const out = new Uint8Array(hex.length / 2);
  for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.substr(i * 2, 2), 16);
  return out;
}

// crypto 模块
const cryptoModule: any = {
  constants: {
    RSA_PKCS1_PADDING: 1,
    RSA_NO_PADDING: 3,
    RSA_PKCS1_OAEP_PADDING: 4,
    RSA_PSS_SALTLEN_DIGEST: -1,
    RSA_PSS_SALTLEN_MAX_SIGN: -2,
    RSA_PSS_SALTLEN_AUTO: -1,
    POINT_CONVERSION_COMPRESSED: 2,
    POINT_CONVERSION_UNCOMPRESSED: 4,
    POINT_CONVERSION_HYBRID: 6,
    defaultCoreCipherList: '',
    defaultCipherList: '',
  },
  createHash: function(algo: string) {
    const chunks: Uint8Array[] = [];
    return {
      update: function(chunk: any) { chunks.push(toBuffer(chunk)); return this; },
      digest: function(encoding?: string) {
        const combined = chunks.length === 1 ? chunks[0] : (() => { const total = chunks.reduce((a, b) => a + b.length, 0); const out = new Uint8Array(total); let off = 0; for (const c of chunks) { out.set(c, off); off += c.length; } return out; })();
        return bufferToString(simpleHash(algo, combined), encoding);
      },
    };
  },
  createHmac: function(algo: string, key: any) {
    const chunks: Uint8Array[] = [];
    const keyBuf = toBuffer(key);
    return {
      update: function(chunk: any) { chunks.push(toBuffer(chunk)); return this; },
      digest: function(encoding?: string) {
        const data = chunks.length === 1 ? chunks[0] : (() => { const total = chunks.reduce((a, b) => a + b.length, 0); const out = new Uint8Array(total); let off = 0; for (const c of chunks) { out.set(c, off); off += c.length; } return out; })();
        const blockSize = algo === 'sha256' || algo === 'sha512' ? 128 : 64;
        const k = keyBuf.length > blockSize ? simpleHash(algo, keyBuf) : keyBuf;
        const iPadded = new Uint8Array(blockSize);
        const oPadded = new Uint8Array(blockSize);
        for (let i = 0; i < k.length; i++) { iPadded[i] = k[i] ^ 0x36; oPadded[i] = k[i] ^ 0x5c; }
        for (let i = k.length; i < blockSize; i++) { iPadded[i] = 0x36; oPadded[i] = 0x5c; }
        const inner = new Uint8Array(iPadded.length + data.length);
        inner.set(iPadded); inner.set(data, iPadded.length);
        const innerHash = simpleHash(algo, inner);
        const outer = new Uint8Array(oPadded.length + innerHash.length);
        outer.set(oPadded); outer.set(innerHash, oPadded.length);
        return bufferToString(simpleHash(algo, outer), encoding);
      },
    };
  },
  randomBytes: function(n: number, cb?: (err: Error | null, buf: any) => void) {
    const arr = new Uint8Array(n);
    if (typeof (globalThis as any).crypto !== 'undefined' && (globalThis as any).crypto.getRandomValues) {
      (globalThis as any).crypto.getRandomValues(arr);
    } else {
      for (let i = 0; i < n; i++) arr[i] = Math.floor(Math.random() * 256);
    }
    const buf: any = {
      buffer: arr,
      length: n,
      toString: function(enc?: string) {
        if (enc === 'hex') {
          let s = '';
          for (let i = 0; i < n; i++) s += arr[i].toString(16).padStart(2, '0');
          return s;
        }
        if (enc === 'base64') {
          let s = '';
          for (let i = 0; i < n; i++) s += String.fromCharCode(arr[i]);
          return btoa(s);
        }
        return new TextDecoder().decode(arr);
      },
    };
    if (cb) { setTimeout(() => cb(null, buf), 0); return undefined; }
    return buf;
  },
  randomUUID: function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      const r = Math.random() * 16 | 0;
      const v = c === 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  },
  createCipheriv: function(algo: string, key: any, _iv: any) {
    const keyBuf = toBuffer(key);
    return {
      update: function(data: any) {
        const dataBuf = toBuffer(data);
        if (algo === 'aes-128-ecb') return aesEcbEncrypt(dataBuf, keyBuf);
        return dataBuf;
      },
      final: function() { return new Uint8Array(0); },
    };
  },
  createDecipheriv: function(algo: string, key: any, _iv: any) {
    const keyBuf = toBuffer(key);
    return {
      update: function(data: any) {
        const dataBuf = toBuffer(data);
        if (algo === 'aes-128-ecb') return aesEcbDecrypt(dataBuf, keyBuf);
        return dataBuf;
      },
      final: function() { return new Uint8Array(0); },
    };
  },
  publicEncrypt: function(options: any, data: any) {
    const keyPem = typeof options === 'string' ? options : options.key;
    const dataBuf = toBuffer(data);
    return rsaPublicEncrypt(dataBuf, keyPem);
  },
  privateDecrypt: function() { return new Uint8Array(0); },
  privateEncrypt: function() { return new Uint8Array(0); },
  createSign: function() { return { update: function() { return this; }, sign: function() { return new Uint8Array(0); } }; },
  createVerify: function() { return { update: function() { return this; }, verify: function() { return true; } }; },
  getCiphers: () => ['aes-128-cbc', 'aes-128-ecb'],
  getHashes: () => ['md5', 'sha1', 'sha256'],
  pbkdf2: function() {},
  pbkdf2Sync: function() { return new Uint8Array(0); },
  createDiffieHellman: function() { return { generateKeys: () => new Uint8Array(0), computeSecret: () => new Uint8Array(0), getPrime: () => new Uint8Array(0), getGenerator: () => new Uint8Array(0) }; },
  createECDH: function() { return { generateKeys: () => new Uint8Array(0), computeSecret: () => new Uint8Array(0), getPublicKey: () => new Uint8Array(0) }; },
  timingSafeEqual: function(a: any, b: any) { const al = toBuffer(a); const bl = toBuffer(b); if (al.length !== bl.length) return false; let d = 0; for (let i = 0; i < al.length; i++) d |= al[i] ^ bl[i]; return d === 0; },
};

// 完整的 polyfill 注册表
export function createNodePolyfills(): Record<string, any> {
  const streamMod: any = {
    Stream: createStreamBase(),
    Readable: createReadable(),
    Writable: createWritable(),
    Duplex: createTransform(),
    Transform: createTransform(),
    PassThrough: createPassThrough(),
    pipeline: (_a: any, b: any, cb?: () => void) => { if (cb) cb(); return b; },
    finished: (_s: any, cb: () => void) => { cb(); },
  };
  streamMod.Stream.prototype = Object.create(createEventEmitter());
  streamMod.Readable.prototype = Object.create(streamMod.Stream.prototype);
  streamMod.Writable.prototype = Object.create(streamMod.Stream.prototype);
  streamMod.Duplex.prototype = Object.create(streamMod.Stream.prototype);
  streamMod.Transform.prototype = Object.create(streamMod.Duplex.prototype);
  streamMod.PassThrough.prototype = Object.create(streamMod.Transform.prototype);

  const bufferModule: any = {
    from: (x: any) => {
      if (x instanceof Uint8Array) return x;
      if (typeof x === 'string') return new TextEncoder().encode(x);
      if (Array.isArray(x)) return new Uint8Array(x);
      return new Uint8Array(x || 0);
    },
    alloc: (n: number) => new Uint8Array(n),
    allocUnsafe: (n: number) => new Uint8Array(n),
    isBuffer: () => false,
    concat: (arrs: any[]) => {
      const total = arrs.reduce((a, b) => a + (b?.length || 0), 0);
      const merged = new Uint8Array(total);
      let offset = 0;
      for (const c of arrs) { if (c) { merged.set(c, offset); offset += c.length; } }
      return merged;
    },
    byteLength: (x: any) => typeof x === 'string' ? new TextEncoder().encode(x).length : (x?.length || 0),
    compare: (_a: any, _b: any) => 0,
    isEncoding: () => true,
  };

  return {
    http: createHttpModule(false),
    https: createHttpModule(true),
    http2: createHttpModule(true),
    stream: streamMod,
    util: utilModule,
    events: { EventEmitter: function() { return createEventEmitter(); } },
    crypto: cryptoModule,
    url: {
      parse: parseUrl,
      format: (o: any) => o.href || `${o.protocol}//${o.host}${o.path || o.pathname || ''}`,
      resolve: (_from: string, to: string) => { try { return new URL(to, _from).href; } catch { return to; } },
      URL: typeof (globalThis as any).URL !== 'undefined' ? (globalThis as any).URL : function() {},
      URLSearchParams: typeof (globalThis as any).URLSearchParams !== 'undefined' ? (globalThis as any).URLSearchParams : function() {},
    },
    zlib: {
      Z_NO_FLUSH: 0,
      Z_PARTIAL_FLUSH: 1,
      Z_SYNC_FLUSH: 2,
      Z_FULL_FLUSH: 3,
      Z_FINISH: 4,
      Z_BLOCK: 5,
      Z_TREES: 6,
      Z_OK: 0,
      Z_STREAM_END: 1,
      Z_NEED_DICT: 2,
      Z_ERRNO: -1,
      Z_STREAM_ERROR: -2,
      Z_DATA_ERROR: -3,
      Z_MEM_ERROR: -4,
      Z_BUF_ERROR: -5,
      Z_VERSION_ERROR: -6,
      Z_NO_COMPRESSION: 0,
      Z_BEST_SPEED: 1,
      Z_BEST_COMPRESSION: 9,
      Z_DEFAULT_COMPRESSION: -1,
      Z_DEFAULT_STRATEGY: 0,
      Z_FILTERED: 1,
      Z_HUFFMAN_ONLY: 2,
      Z_RLE: 3,
      Z_FIXED: 4,
      DEFLATE: 1,
      INFLATE: 2,
      GZIP: 3,
      GUNZIP: 4,
      DEFLATERAW: 5,
      INFLATERAW: 6,
      UNZIP: 7,
      BROTLI_DECODE: 8,
      BROTLI_ENCODE: 9,
      gunzipSync: (d: any) => d,
      inflateSync: (d: any) => d,
      deflateSync: (d: any) => d,
      gzipSync: (d: any) => d,
      deflateRaw: (d: any, cb: (err: Error | null, out: any) => void) => { setTimeout(() => cb(null, d), 0); },
      inflateRaw: (d: any, cb: (err: Error | null, out: any) => void) => { setTimeout(() => cb(null, d), 0); },
      deflateRawSync: (d: any) => d,
      inflateRawSync: (d: any) => d,
      gunzip: (d: any, cb: (err: Error | null, out: any) => void) => { setTimeout(() => cb(null, d), 0); },
      inflate: (d: any, cb: (err: Error | null, out: any) => void) => { setTimeout(() => cb(null, d), 0); },
      createGunzip: () => { const p: any = Object.create(streamMod !== undefined ? streamMod.Transform.prototype : {}); p.write = () => true; p.end = function() { this.emit && this.emit('end'); return this; }; return p; },
      createInflate: () => { const p: any = Object.create(streamMod !== undefined ? streamMod.Transform.prototype : {}); p.write = () => true; p.end = function() { this.emit && this.emit('end'); return this; }; return p; },
      createGzip: () => { const p: any = Object.create(streamMod !== undefined ? streamMod.Transform.prototype : {}); p.write = () => true; p.end = function() { this.emit && this.emit('end'); return this; }; return p; },
    },
    path: {
      join: function() { return Array.prototype.slice.call(arguments).filter(Boolean).join('/').replace(/\/+/g, '/'); },
      resolve: function() { return Array.prototype.slice.call(arguments).filter(Boolean).join('/'); },
      dirname: (p: string) => String(p).split('/').slice(0, -1).join('/') || '/',
      basename: (p: string, ext?: string) => { const base = String(p).split('/').pop() || ''; return ext && base.endsWith(ext) ? base.slice(0, -ext.length) : base; },
      extname: (p: string) => { const m = String(p).match(/\.[^.]*$/); return m ? m[0] : ''; },
      sep: '/', delimiter: ':',
      parse: (p: string) => { const parts = String(p).split('/'); return { root: '/', dir: parts.slice(0, -1).join('/'), base: parts[parts.length - 1], ext: '', name: parts[parts.length - 1].replace(/\.[^.]*$/, '') }; },
      normalize: (p: string) => p,
      isAbsolute: (p: string) => p && p[0] === '/',
      relative: (_from: string, to: string) => to,
    },
    fs: {
      readFileSync: () => '',
      writeFileSync: () => {},
      existsSync: () => false,
      createWriteStream: () => { const s = Object.create(streamMod.Writable.prototype); s.write = () => true; s.end = function() { this.emit && this.emit('finish'); return this; }; return s; },
      createReadStream: () => { const s = Object.create(streamMod.Readable.prototype); s.pipe = (d: any) => { s.emit && s.emit('end'); return d; }; return s; },
      readFile: (_path: any, enc: any, cb: (err: Error | null, data: any) => void) => { if (typeof enc === 'function') cb = enc; setTimeout(() => cb(null, ''), 0); },
      writeFile: (_p: any, _d: any, cb?: (err: Error | null) => void) => { if (typeof cb === 'function') setTimeout(() => cb(null), 0); },
      mkdirSync: () => {},
      statSync: () => ({ isDirectory: () => false, isFile: () => true, size: 0, mtime: new Date() }),
      unlinkSync: () => {},
      promises: {
        readFile: async () => '',
        writeFile: async () => {},
        mkdir: async () => {},
      },
    },
    os: {
      platform: () => 'browser',
      type: () => 'Browser',
      release: () => '1.0',
      tmpdir: () => '/tmp',
      homedir: () => '/',
      EOL: '\n',
      arch: () => 'x64',
      cpus: () => [],
      totalmem: () => 0,
      freemem: () => 0,
    },
    assert: {
      ok: function() {},
      equal: function() {},
      deepEqual: function() {},
      strictEqual: function() {},
      throws: function() {},
      notEqual: function() {},
      ifError: function() {},
    },
    dns: {
      lookup: (_host: string, cb: (err: Error | null, addr: string, family: number) => void) => { setTimeout(() => cb(null, '127.0.0.1', 4), 0); },
      resolve: (_host2: string, cb: (err: Error | null, addrs: string[]) => void) => { setTimeout(() => cb(null, ['127.0.0.1']), 0); },
    },
    buffer: bufferModule,
    // 'Buffer' is already an alias for bufferModule, but some plugins require('buffer').Buffer
    Buffer: bufferModule,
    string_decoder: {
      StringDecoder: function() {
        this.write = function(x: any) { return typeof x === 'string' ? x : new TextDecoder().decode(x); };
        this.end = function(x: any) { return x ? this.write(x) : ''; };
      },
    },
    querystring: {
      parse: (s: string) => {
        const out: Record<string, string> = {};
        const q = String(s || '').replace(/^\?/, '');
        if (!q) return out;
        for (const pair of q.split('&')) {
          const [k, v] = pair.split('=');
          if (k) out[decodeURIComponent(k)] = v !== undefined ? decodeURIComponent(v) : '';
        }
        return out;
      },
      stringify: (obj: any) => Object.entries(obj || {}).map(([k, v]) => encodeURIComponent(String(k)) + '=' + encodeURIComponent(String(v))).join('&'),
    },
    tty: { isatty: () => false, ReadStream: function() {}, WriteStream: function() {} },
    net: {
      createServer: () => ({ listen: () => {}, close: () => {}, on: function() { return this; } }),
      createConnection: () => createEventEmitter(),
      Socket: function() { return createEventEmitter(); },
    },
    tls: {
      connect: () => createEventEmitter(),
      TLSSocket: function() { return createEventEmitter(); },
      createSecureContext: () => ({}),
    },
    child_process: {
      spawn: () => createEventEmitter(),
      exec: (_cmd: string, cb: (err: Error | null, stdout: string, stderr: string) => void) => setTimeout(() => cb(null, '', ''), 0),
      execSync: () => '',
    },
    cluster: { isWorker: false, isMaster: true, fork: function() {}, on: function() { return this; } },
    module: { Module: function() {} },
    vm: { runInNewContext: (code: string, sandbox: any) => { const fn = new Function(...Object.keys(sandbox || {}), code); return fn(...Object.values(sandbox || {})); } },
    perf_hooks: { performance: typeof (globalThis as any).performance !== 'undefined' ? (globalThis as any).performance : { now: () => Date.now() } },
    console,
  };
}

// 为给定的 webpack bundle 代码提供完整的沙箱环境
export function createSandboxRequire(): (id: string) => any {
  const polyfills = createNodePolyfills();
  return function(id: string): any {
    if (polyfills[id]) return polyfills[id];
    // 处理子路径，如 stream/transform, crypto/hash 等
    const base = id.split('/')[0];
    if (polyfills[base]) return polyfills[base];
    return {};
  };
}
