import { assert } from "../../../assert.js";

/**
 * Build a `Map<vertex_id, tet_id[]>` enumerating every live tet that
 * contains each vertex. One full pass over the mesh; the result lets
 * subsequent per-vertex queries run in O(deg) instead of O(N).
 *
 * Useful when the caller is about to perform many per-vertex queries —
 * e.g. boundary-status checks or 1-ring quality evaluations across a whole
 * mesh during a quality-improvement pass. Without the cache, each query
 * has to scan every live tet (see
 * {@link tetrahedral_mesh_find_tets_attached_to_vertex} and
 * {@link tetrahedral_mesh_vertex_is_boundary}), which compounds to O(N²)
 * over a full pass.
 *
 * The map is a SNAPSHOT: it reflects mesh state at build time. Any flips,
 * deletions or appends that happen afterwards will leave it stale. Callers
 * must either rebuild after each mutation or accept the staleness (for
 * boundary checks the cache is flip-invariant, so a once-per-pass rebuild
 * is safe; for queries that need the exact current 1-ring, the caller
 * should filter through `mesh.exists` and rebuild after mutations they
 * care about).
 *
 * Cost: O(N) where N is `mesh.count`.
 *
 * @param {TetrahedralMesh} mesh
 * @returns {Map<number, number[]>}
 */
export function tetrahedral_mesh_build_vertex_to_tets_map(mesh) {
    assert.defined(mesh, 'mesh');

    /** @type {Map<number, number[]>} */
    const map = new Map();

    mesh.forEach((tet, m) => {
        for (let i = 0; i < 4; i++) {
            const v = m.getVertexIndex(tet, i);
            let bucket = map.get(v);
            if (bucket === undefined) {
                bucket = [];
                map.set(v, bucket);
            }
            bucket.push(tet);
        }
    });

    return map;
}
