import Vector3 from "../../../../core/geom/Vector3.js";
import Vector4 from "../../../../core/geom/Vector4.js";
import { max2 } from "../../../../core/math/max2.js";
import { isMesh } from "./isMesh.js";
import { rootObject3DFastMatrixUpdate } from "../../../graphics/ecs/mesh/rootObject3DFastMatrixUpdate.js";

/**
 *
 * @param {Object3D} o
 * @returns {Vector4} center is x,y,z while radius is w
 */
export function computeObjectBoundingSphere(o) {
    /*
    TODO: There are better ways of doing this:
    https://github.com/CGAL/cgal/blob/c68cf8fc4c850f8cd84c6900faa781286a7117ed/Bounding_volumes/include/CGAL/Min_sphere_of_spheres_d/Min_sphere_of_spheres_d_impl.h
    */

    /**
     * Individual geometry-bounding spheres comprising the object
     * @type {Sphere[]}
     */
    const balls = [];

    rootObject3DFastMatrixUpdate(o);

    o.traverse(m => {
        if (isMesh(m)) {
            const geometry = m.geometry;

            const sphere = geometry.boundingSphere.clone();

            if (m !== o) {
                sphere.applyMatrix4(m.matrixWorld);
            }

            balls.push(sphere);
        }
    });

    // compute overall center
    const center = new Vector3();

    const numBalls = balls.length;
    for (let i = 0; i < numBalls; i++) {
        const sphere = balls[i];
        center.add(sphere.center);
    }

    if (numBalls > 0) {
        center.multiplyScalar(1 / numBalls);
    }

    // compute radius of the main sphere by computing the largest distance from the overall center to the edge of each individual sphere
    let radius = 0;

    for (let i = 0; i < numBalls; i++) {
        const sphere = balls[i];

        const distance_to_ball_edge = center.distanceTo(sphere.center) + sphere.radius;

        radius = max2(radius, distance_to_ball_edge);
    }

    return new Vector4(
        center.x,
        center.y,
        center.z,
        radius
    );
}
