// Drill into the head/mouth region. Front = +Z. Looks at body vertices in the
// front quarter and reports the vertical (Y) profile from nose back, plus the
// lowest points near the mouth — to test "lower lip sits below the body".
import { NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';

const io = new NodeIO().registerExtensions(ALL_EXTENSIONS);
const doc = await io.read(process.argv[2]);
const root = doc.getRoot();
const joints = root.listSkins()[0].listJoints();
const isBody = joints.map((n) => n.getName().startsWith('Spine'));

const mesh = root.listMeshes()[0];
const prim = mesh.listPrimitives().reduce((a, b) => (b.getIndices().getCount() > a.getIndices().getCount() ? b : a));
const pos = prim.getAttribute('POSITION');
const jA = prim.getAttribute('JOINTS_0'), wA = prim.getAttribute('WEIGHTS_0');
const n = pos.getCount();

const p = [0, 0, 0], j = [0, 0, 0, 0], w = [0, 0, 0, 0];
// bucket body vertices by Z slab from nose (+Z) backward; track Y min/max per slab
const slabs = {};
let bodyMinY = 1e9, bodyMaxY = -1e9;
const front = []; // {x,y,z} of front-most body verts
for (let i = 0; i < n; i++) {
  jA.getElement(i, j); wA.getElement(i, w);
  let best = 0, bw = -1; for (let k = 0; k < 4; k++) if (w[k] > bw) { bw = w[k]; best = j[k]; }
  if (!isBody[best]) continue;
  pos.getElement(i, p);
  bodyMinY = Math.min(bodyMinY, p[1]); bodyMaxY = Math.max(bodyMaxY, p[1]);
  const slab = Math.round(p[2] * 10) / 10;
  const e = slabs[slab] || (slabs[slab] = { c: 0, ymin: 1e9, ymax: -1e9 });
  e.c++; e.ymin = Math.min(e.ymin, p[1]); e.ymax = Math.max(e.ymax, p[1]);
  if (p[2] > 0.30) front.push([p[0], p[1], p[2]]);
}
console.log(`body Y range overall: ${bodyMinY.toFixed(3)} .. ${bodyMaxY.toFixed(3)}\n`);
console.log('Z slab (nose=+Z → tail)   bodyY min..max   (height)');
for (const z of Object.keys(slabs).map(Number).sort((a, b) => b - a)) {
  const e = slabs[z];
  console.log(`  z=${z.toFixed(1).padStart(5)}  n=${String(e.c).padStart(4)}  Y ${e.ymin.toFixed(3)} .. ${e.ymax.toFixed(3)}  (${(e.ymax - e.ymin).toFixed(3)})`);
}
// the lowest front verts (potential lower lip / jaw)
front.sort((a, b) => a[1] - b[1]);
console.log('\nlowest 6 front (z>0.30) body verts  [x, y, z]:');
for (const v of front.slice(0, 6)) console.log('   ', v.map((x) => x.toFixed(3).padStart(7)).join(', '));
console.log('frontmost 6 (max z) body verts  [x, y, z]:');
front.sort((a, b) => b[2] - a[2]);
for (const v of front.slice(0, 6)) console.log('   ', v.map((x) => x.toFixed(3).padStart(7)).join(', '));
