import { TRIANGLE_FEATURE_ID_OFFSET, TRIANGLE_FLOAT_STRIDE } from "./triangle_buffer_layout.js";

/**
 * Write the mesh's surface triangles that may overlap the given query
 * AABB into `output`, starting at float-index `offset`.
 *
 * Each triangle occupies {@link TRIANGLE_FLOAT_STRIDE} consecutive floats:
 *   [+0..+2]  vA.xyz   (shape's body-local frame, i.e. read directly from
 *                       {@link MeshShape3D#positions})
 *   [+3..+5]  vB.xyz
 *   [+6..+8]  vC.xyz
 *   [+9]      feature_id   (the surface triangle's index)
 *
 * Triangles are AABB-filtered: a triangle is emitted iff its tight AABB
 * (min/max across its 3 vertices) overlaps the query AABB. This is a
 * linear O(N) scan over the mesh's surface triangles — no surface-BVH
 * yet (the existing BVH on MeshShape3D is over the *tet* decomposition
 * used by `contains_point`, with different leaf semantics). For meshes
 * up to a few thousand triangles the linear scan is comfortably faster
 * than a BVH would be after broadphase has already given us a tight
 * query AABB; we can graduate to a per-mesh surface BVH later.
 *
 * Determinism: triangles are emitted in the natural index order, so
 * feature_id values inside `output` rise monotonically over a single
 * call. The narrowphase relies on this for stable contact-manifold
 * pairing across frames.
 *
 * Caller is responsible for ensuring
 *   `output.length - offset >= shape.indices.length / 3 * TRIANGLE_FLOAT_STRIDE`
 * in the worst case (every triangle overlaps).
 *
 * @param {Float64Array} output
 * @param {number} offset float-index into output
 * @param {MeshShape3D} shape
 * @param {number} aabb_min_x  query AABB in shape's body-local frame
 * @param {number} aabb_min_y
 * @param {number} aabb_min_z
 * @param {number} aabb_max_x
 * @param {number} aabb_max_y
 * @param {number} aabb_max_z
 * @returns {number} number of triangles written
 */
export function mesh_enumerate_triangles(
    output, offset, shape,
    aabb_min_x, aabb_min_y, aabb_min_z,
    aabb_max_x, aabb_max_y, aabb_max_z
) {
    const positions = shape.positions;
    const indices = shape.indices;

    const tri_count = (indices.length / 3) | 0;
    if (tri_count === 0) {
        return 0;
    }

    let count = 0;
    let cursor = offset;

    for (let t = 0; t < tri_count; t++) {
        const i_a = indices[t * 3    ] * 3;
        const i_b = indices[t * 3 + 1] * 3;
        const i_c = indices[t * 3 + 2] * 3;

        const ax = positions[i_a    ]; const ay = positions[i_a + 1]; const az = positions[i_a + 2];
        const bx = positions[i_b    ]; const by = positions[i_b + 1]; const bz = positions[i_b + 2];
        const cx = positions[i_c    ]; const cy = positions[i_c + 1]; const cz = positions[i_c + 2];

        // tight per-triangle AABB
        const tri_min_x = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx);
        if (tri_min_x > aabb_max_x) continue;
        const tri_max_x = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx);
        if (tri_max_x < aabb_min_x) continue;

        const tri_min_y = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy);
        if (tri_min_y > aabb_max_y) continue;
        const tri_max_y = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);
        if (tri_max_y < aabb_min_y) continue;

        const tri_min_z = az < bz ? (az < cz ? az : cz) : (bz < cz ? bz : cz);
        if (tri_min_z > aabb_max_z) continue;
        const tri_max_z = az > bz ? (az > cz ? az : cz) : (bz > cz ? bz : cz);
        if (tri_max_z < aabb_min_z) continue;

        output[cursor    ] = ax; output[cursor + 1] = ay; output[cursor + 2] = az;
        output[cursor + 3] = bx; output[cursor + 4] = by; output[cursor + 5] = bz;
        output[cursor + 6] = cx; output[cursor + 7] = cy; output[cursor + 8] = cz;
        output[cursor + TRIANGLE_FEATURE_ID_OFFSET] = t;

        cursor += TRIANGLE_FLOAT_STRIDE;
        count++;
    }

    return count;
}
