import { tetrahedral_mesh_to_bvh } from "../tetrahedra/bvh/tetrahedral_mesh_to_bvh.js";
import { compute_tetrahedral_mesh_from_surface } from "../tetrahedra/compute_tetrahedral_mesh_from_surface.js";
import { BinaryTopology } from "../topology/struct/binary/BinaryTopology.js";
import { bt_mesh_from_indexed_geometry } from "../topology/struct/binary/io/bt_mesh_from_indexed_geometry.js";
import { MeshShape3D } from "./MeshShape3D.js";

/**
 * Build a {@link MeshShape3D} from a Three-style indexed triangle buffer.
 *
 * Pipeline:
 *  1. {@link bt_mesh_from_indexed_geometry} reconstructs a
 *     {@link BinaryTopology} (vertex / edge / loop / face cycles).
 *  2. {@link compute_tetrahedral_mesh_from_surface} tetrahedralises the
 *     volume enclosed by the surface, carving away exterior tets.
 *  3. The tet mesh is **compacted** — the carving pass leaves the free
 *     list populated with low-index slots, and downstream consumers
 *     (`tetrahedral_mesh_to_bvh` iterates by index, the shape's
 *     `recompute_cached` does the same) expect a hole-free range.
 *     Compaction relocates live tets so indices `[0, count)` are dense.
 *  4. The flat positions + indices are kept verbatim on the shape for
 *     fast support-function and triangle-distance queries.
 *  5. A {@link BVH} is built over the tet AABBs, used by
 *     {@link MeshShape3D#contains_point} for O(log N) point-in-mesh
 *     queries that correctly handle disconnected meshes (which the
 *     previous tet-walker did not).
 *
 * The caller's buffers are NOT cloned — they're attached to the shape
 * directly. Don't mutate them after handing them in.
 *
 * @param {Float32Array} positions flat `(x, y, z)` per vertex
 * @param {Uint32Array}  indices  three uint32 per triangle (CCW winding)
 * @returns {MeshShape3D}
 */
export function shape_mesh_from_geometry(positions, indices) {
    const shape = new MeshShape3D();
    shape.positions = positions;
    shape.indices = indices;

    // 1. BinaryTopology from the indexed buffer.
    const topology = new BinaryTopology();
    bt_mesh_from_indexed_geometry(topology, indices, positions);

    // 2. Tetrahedralise. interior_steiner_cells_per_dim = 0 — for
    //    collision queries the inside/outside oracle only needs
    //    surface-vertex tets; interior Steiner points add cost without
    //    changing the contains_point result.
    shape.tet_positions = compute_tetrahedral_mesh_from_surface(shape.tet_mesh, topology, 0);

    // 3. Compact. The carve pass freed slots in the tet mesh's
    //    allocator; compaction repacks live tets into a dense
    //    [0, count) range. Without this, `tetrahedral_mesh_to_bvh`
    //    iterates "tet index 0..count" and treats freed indices as if
    //    they were live tets — produces phantom BVH leaves with stale
    //    vertex data.
    shape.tet_mesh.compact();

    // 4. BVH over tet AABBs for the point-in-mesh query path.
    tetrahedral_mesh_to_bvh(shape.tet_bvh, shape.tet_mesh, shape.tet_positions);

    // 5. Refresh cached bbox / volume / surface area.
    shape.recompute_cached();

    return shape;
}
