/**
 * Closed-form contact generation for two spheres positioned in world space.
 * Returns whether the spheres overlap. On overlap, `out` is populated with
 * `[nx, ny, nz, depth]` where the normal (unit length) points from B toward A
 * and `depth` is the positive penetration distance.
 *
 * Each sphere's radius is passed explicitly (`radius_a` / `radius_b`) — the
 * caller reads it from the shape (`SphereShape3D.radius`; 1 for the
 * {@link UnitSphereShape3D} special case). Any scaling on the body's transform
 * is irrelevant under our "no scale on physics transforms" assumption.
 *
 * Centres-coincident is a singular case for the general normal but is
 * resolved here by picking +X as a deterministic tie-break direction.
 *
 * @param {number[]|Float64Array} out length >= 4
 * @param {number} ax
 * @param {number} ay
 * @param {number} az
 * @param {number} bx
 * @param {number} by
 * @param {number} bz
 * @param {number} radius_a
 * @param {number} radius_b
 * @returns {boolean} true if spheres overlap
 */
export function sphere_sphere_contact(out, ax, ay, az, bx, by, bz, radius_a, radius_b) {
    const dx = ax - bx;
    const dy = ay - by;
    const dz = az - bz;
    const dist_sqr = dx * dx + dy * dy + dz * dz;

    const sum = radius_a + radius_b;
    if (dist_sqr >= sum * sum) {
        return false;
    }

    const dist = Math.sqrt(dist_sqr);
    if (dist > 0) {
        const inv = 1 / dist;
        out[0] = dx * inv;
        out[1] = dy * inv;
        out[2] = dz * inv;
    } else {
        // Centres coincide. Pick +X deterministically (no RNG); penetration is
        // the full sum of radii.
        out[0] = 1;
        out[1] = 0;
        out[2] = 0;
    }
    out[3] = sum - dist;
    return true;
}
