// =====================================================================
// CC GPU packers.
//
// Originally hosted the full CC per-vertex eval (CC_GPU_PATCH_WGSL +
// CcGpuPatchCtx) -- the validation pipeline that took (triId, bary)
// cases, dispatched a compute shader, and returned (P, N) per case.
//
// Phase E of the CC -> PASS_B consolidation merged that eval into
// PASS_B itself (see cc_gpu_eval_from_topo.js and the evalCCFromTopo
// branch inside PASS_B_WGSL). Phase F3 deleted the standalone shader
// and context class -- this file is now reduced to the JS-side
// packers that build the byte layouts the unified eval reads from
// `topo`. They are called from topo.js's appendCcStaticToTopoBlob
// (per Phase B/C).
//
// Filename stayed `cc_gpu_patch.js` to avoid a rename ripple through
// index.html's <script src>; the file's role is now strictly "byte
// packers", no shader code.
// =====================================================================
'use strict';

// =====================================================================
// JS packers.
// =====================================================================
function packPolyInfoTable(ccState) {
  const polyInfo = ccState.patches.m_polyInfo;
  const N = polyInfo.length;
  const buf = new ArrayBuffer(N * 128);
  const u32 = new Uint32Array(buf);
  const f32 = new Float32Array(buf);
  for (let i = 0; i < N; i++) {
    const p = polyInfo[i];
    const base = i * 32;
    u32[base + 0] = p.m_type;
    u32[base + 1] = p.m_subdivLevel;
    const qg = p.m_quadRegionGrid;
    if (qg) {
      u32[base + 2] = qg.m_regionMask >>> 0;
      u32[base + 3] = qg.m_regionDataStart >>> 0;
      u32[base + 4] = qg.m_regionDataNum >>> 0;
      u32[base + 5] = qg.m_pointsStart >>> 0;
    }
    u32[base + 6] = p.m_triCenterIndex >>> 0;
    f32[base + 8]  = p.m_edgeSharpness[0];
    f32[base + 9]  = p.m_edgeSharpness[1];
    f32[base + 10] = p.m_edgeSharpness[2];
    f32[base + 11] = p.m_edgeSharpness[3];
    // Triangle path: 3 corner region grids at offsets 16, 20, 24.
    const trg = p.m_triRegionGrids;
    if (trg) {
      for (let k = 0; k < 3; k++) {
        const g = trg[k];
        const off = base + 16 + k * 4;
        u32[off + 0] = g.m_regionMask >>> 0;
        u32[off + 1] = g.m_regionDataStart >>> 0;
        u32[off + 2] = g.m_regionDataNum >>> 0;
        u32[off + 3] = g.m_pointsStart >>> 0;
      }
    }
  }
  return buf;
}

function packTriPatchMapTable(ccState) {
  const tpm = ccState.triPatchMap;
  const N = tpm.length;
  const buf = new ArrayBuffer(N * 32);
  const u32 = new Uint32Array(buf);
  const f32 = new Float32Array(buf);
  for (let i = 0; i < N; i++) {
    const e = tpm[i];
    const base = i * 8;
    u32[base + 0] = e.patchIter >>> 0;
    for (let k = 0; k < 6; k++) f32[base + 1 + k] = e.uvBasis[k];
    u32[base + 7] = 0;
  }
  return buf;
}

function flattenCpRedirect(ccState) {
  return new Int32Array(ccState.patches.m_weightInflData.m_regularAndIrregularPoints);
}

// Pack regionData: 8 u32 per RegionInfo.
function packRegionDataTable(ccState) {
  const rd = ccState.patches.m_regionData;
  const N = rd.length;
  const buf = new ArrayBuffer(Math.max(N, 1) * 32);
  const u32 = new Uint32Array(buf);
  const i32 = new Int32Array(buf);
  for (let i = 0; i < N; i++) {
    const r = rd[i];
    const base = i * 8;
    i32[base + 0] = r.m_irregularIndex;
    u32[base + 1] = r.m_irregularPolyIndex >>> 0;
    u32[base + 2] = r.m_irregularSubdivLevel >>> 0;
    u32[base + 3] = r.m_rotation >>> 0;
    u32[base + 4] = r.m_irregularRegionScale >>> 0;
  }
  return buf;
}

// Pack IrregularInfo combined: 16 u32 per entry.
function packIrregularInfoTable(ccState) {
  const wi = ccState.patches.m_irregularWedgeInfo;
  const ri = ccState.patches.m_weightInflData.m_runtimeIrregularInfo;
  const ws = ccState.wedgeStartPoints;
  const wn = ccState.wedgeNumDstPoints;
  const wl = ccState.wedgeLevels;
  const N = wi.length;
  const buf = new ArrayBuffer(Math.max(N, 1) * 64);
  const u32 = new Uint32Array(buf);
  const i32 = new Int32Array(buf);
  const f32 = new Float32Array(buf);
  for (let i = 0; i < N; i++) {
    const w = wi[i];
    const r = ri[i];
    const base = i * 16;
    u32[base + 0] = w.m_centerVertex >>> 0;
    i32[base + 1] = w.m_centerTrianglePoly;
    i32[base + 2] = w.m_centerTriangleLimitOffset;
    u32[base + 3] = r.m_valence >>> 0;
    u32[base + 4] = r.m_isBorder ? 1 : 0;
    i32[base + 5] = r.m_edgeSharpnessStart;
    u32[base + 6] = ws[i] >>> 0;
    u32[base + 7] = wn[i] >>> 0;
    f32[base + 8] = wl[i];
  }
  return buf;
}

function flattenIrregularEdgeSharpness(ccState) {
  const a = ccState.patches.m_weightInflData.m_irregularEdgeSharpness;
  const out = new Float32Array(Math.max(a.length, 1));
  for (let i = 0; i < a.length; i++) out[i] = a[i];
  return out;
}

// Vec3Data combined: cpData (numCp) | fullWedgeDstPoints (totalWedgePts) |
// limitPosData (numLimitPoints) | limitNrmData (numLimitPoints).
// Returns { buffer, cpDataOffsetV3, fullWedgeOffsetV3, limitPosOffsetV3,
//           limitNrmOffsetV3 } -- all in vec3-unit indices.
function packVec3Data(ccState) {
  const cp  = ccState.reusableCpData;
  const fwp = ccState.fullWedgeDstPoints;
  const lp  = ccState.limitPosData;
  const ln  = ccState.limitNrmData;
  const numCp = cp.length;
  const numFwp = fwp.length;
  const numLp = lp.length;
  const numLn = ln.length;
  const total = numCp + numFwp + numLp + numLn;
  const out = new Float32Array(Math.max(total * 3, 3));
  let off = 0;
  const cpDataOffsetV3 = 0;
  for (let i = 0; i < numCp; i++) {
    out[off++] = cp[i][0]; out[off++] = cp[i][1]; out[off++] = cp[i][2];
  }
  const fullWedgeOffsetV3 = numCp;
  for (let i = 0; i < numFwp; i++) {
    out[off++] = fwp[i][0]; out[off++] = fwp[i][1]; out[off++] = fwp[i][2];
  }
  const limitPosOffsetV3 = numCp + numFwp;
  for (let i = 0; i < numLp; i++) {
    out[off++] = lp[i][0]; out[off++] = lp[i][1]; out[off++] = lp[i][2];
  }
  const limitNrmOffsetV3 = numCp + numFwp + numLp;
  for (let i = 0; i < numLn; i++) {
    out[off++] = ln[i][0]; out[off++] = ln[i][1]; out[off++] = ln[i][2];
  }
  return { buffer: out, cpDataOffsetV3, fullWedgeOffsetV3, limitPosOffsetV3, limitNrmOffsetV3 };
}

if (typeof module !== 'undefined' && module.exports) {
  module.exports = {
    packPolyInfoTable, packTriPatchMapTable, flattenCpRedirect,
    packRegionDataTable, packIrregularInfoTable, flattenIrregularEdgeSharpness,
    packVec3Data,
  };
}
