/**
 * Lane J — GLB bytes in, scene graph out.
 *
 * Its own module (rather than living in stage.ts) so the drop pipeline can be
 * imported without dragging in the whole game module graph — stage.ts pulls
 * world/course/machine/paint, and a headless test has no business booting any
 * of that.
 */
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { clone as skeletonClone } from 'three/examples/jsm/utils/SkeletonUtils.js'

/** Parse GLB bytes. Rejects rather than handing back half a model. */
export function loadGlb(bytes: ArrayBuffer): Promise<THREE.Group> {
  const loader = new GLTFLoader()
  return new Promise((resolve, reject) => {
    loader.parse(bytes, '', (gltf) => resolve(gltf.scene), reject)
  })
}

/** Clone an asset safely — SkeletonUtils for anything rigged, plain clone else. */
export function cloneAsset(object: THREE.Object3D): THREE.Object3D {
  let skinned = false
  object.traverse((o) => {
    if ((o as THREE.SkinnedMesh).isSkinnedMesh) skinned = true
  })
  return skinned ? skeletonClone(object) : object.clone(true)
}
