/**
 * ICD Test Runner — CRUD Helpers
 * Shared utilities for CRUD tier tests (ZIP builder, etc.).
 */
(function () {
  'use strict';
  var T = window.ICD;
  if (!T) return;
  if (!T.crud) T.crud = {};

  // ── Minimal ZIP builder (no dependencies) ──
  // Builds a valid ZIP archive from { filename: content } pairs.
  // Content is UTF-8 strings. Returns a Blob suitable for FormData upload.
  var crc32Table = null;

  function crc32(bytes) {
    if (!crc32Table) {
      crc32Table = new Uint32Array(256);
      for (var i = 0; i < 256; i++) {
        var c = i;
        for (var j = 0; j < 8; j++) {
          c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
        }
        crc32Table[i] = c;
      }
    }
    var crc = 0xFFFFFFFF;
    for (var k = 0; k < bytes.length; k++) {
      crc = crc32Table[(crc ^ bytes[k]) & 0xFF] ^ (crc >>> 8);
    }
    return (crc ^ 0xFFFFFFFF) >>> 0;
  }

  T.crud.buildTestZip = function (files) {
    var encoder = new TextEncoder();
    var entries = [];
    var offset = 0;

    // Build file entries
    Object.keys(files).forEach(function (name) {
      var nameBytes = encoder.encode(name);
      var dataBytes = encoder.encode(files[name]);
      var c = crc32(dataBytes);
      entries.push({ name: nameBytes, data: dataBytes, crc: c, offset: offset });
      // Local file header (30) + name + data
      offset += 30 + nameBytes.length + dataBytes.length;
    });

    // Calculate central directory
    var cdOffset = offset;
    var cdSize = 0;
    entries.forEach(function (e) { cdSize += 46 + e.name.length; });

    var totalSize = cdOffset + cdSize + 22; // + EOCD
    var buf = new ArrayBuffer(totalSize);
    var view = new DataView(buf);
    var pos = 0;

    // Write local file headers + data
    entries.forEach(function (e) {
      view.setUint32(pos, 0x04034b50, true); pos += 4;   // signature
      view.setUint16(pos, 20, true); pos += 2;            // version needed
      view.setUint16(pos, 0, true); pos += 2;             // flags
      view.setUint16(pos, 0, true); pos += 2;             // compression (store)
      view.setUint16(pos, 0, true); pos += 2;             // mod time
      view.setUint16(pos, 0, true); pos += 2;             // mod date
      view.setUint32(pos, e.crc, true); pos += 4;         // crc32
      view.setUint32(pos, e.data.length, true); pos += 4; // compressed size
      view.setUint32(pos, e.data.length, true); pos += 4; // uncompressed size
      view.setUint16(pos, e.name.length, true); pos += 2; // name length
      view.setUint16(pos, 0, true); pos += 2;             // extra length
      new Uint8Array(buf, pos, e.name.length).set(e.name); pos += e.name.length;
      new Uint8Array(buf, pos, e.data.length).set(e.data); pos += e.data.length;
    });

    // Write central directory
    entries.forEach(function (e) {
      view.setUint32(pos, 0x02014b50, true); pos += 4;   // signature
      view.setUint16(pos, 20, true); pos += 2;            // version made by
      view.setUint16(pos, 20, true); pos += 2;            // version needed
      view.setUint16(pos, 0, true); pos += 2;             // flags
      view.setUint16(pos, 0, true); pos += 2;             // compression
      view.setUint16(pos, 0, true); pos += 2;             // mod time
      view.setUint16(pos, 0, true); pos += 2;             // mod date
      view.setUint32(pos, e.crc, true); pos += 4;         // crc32
      view.setUint32(pos, e.data.length, true); pos += 4; // compressed size
      view.setUint32(pos, e.data.length, true); pos += 4; // uncompressed size
      view.setUint16(pos, e.name.length, true); pos += 2; // name length
      view.setUint16(pos, 0, true); pos += 2;             // extra length
      view.setUint16(pos, 0, true); pos += 2;             // comment length
      view.setUint16(pos, 0, true); pos += 2;             // disk number
      view.setUint16(pos, 0, true); pos += 2;             // internal attrs
      view.setUint32(pos, 0, true); pos += 4;             // external attrs
      view.setUint32(pos, e.offset, true); pos += 4;      // local header offset
      new Uint8Array(buf, pos, e.name.length).set(e.name); pos += e.name.length;
    });

    // Write EOCD
    view.setUint32(pos, 0x06054b50, true); pos += 4;       // signature
    view.setUint16(pos, 0, true); pos += 2;                // disk number
    view.setUint16(pos, 0, true); pos += 2;                // cd start disk
    view.setUint16(pos, entries.length, true); pos += 2;    // entries on disk
    view.setUint16(pos, entries.length, true); pos += 2;    // total entries
    view.setUint32(pos, cdSize, true); pos += 4;            // cd size
    view.setUint32(pos, cdOffset, true); pos += 4;          // cd offset
    view.setUint16(pos, 0, true);                           // comment length

    return new Blob([buf], { type: 'application/zip' });
  };
})();
