import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
import {
    aabb3_array_intersects_clipping_volume_array
} from "../../../geom/3d/aabb/aabb3_array_intersects_clipping_volume_array.js";

const stack = SCRATCH_UINT32_TRAVERSAL_STACK;

/**
 *
 * @param {number[]} result
 * @param {number} result_offset
 * @param {BinaryUint32BVH} bvh
 * @param {Float32Array|number[]} planes
 * @param {number} planes_offset
 * @param {number} plane_count
 * @returns {number}
 */
export function bvh32_query_user_data_overlaps_clipping_volume(
    result, result_offset,
    bvh,
    planes, planes_offset, plane_count
) {
    let hit_count = 0;

    const binary_node_count = bvh.binary_node_count;

    if (binary_node_count <= 0) {
        // this should not happen
        return 0;
    }

    /**
     *
     * @type {number}
     */
    const stack_top = stack.pointer++;

    /**
     * After performing empirical tests, stack-based depth-first traversal turns out faster than using a queue
     * @type {number}
     */
    stack[stack_top] = 0;

    const last_valid_index = binary_node_count + bvh.leaf_node_count;

    const float32 = bvh.float32;
    const uint32 = bvh.uint32;

    do {
        stack.pointer--;

        // query_bvh_frustum_from_objects.iteration_count++;
        const node_index = stack[stack.pointer];

        const node_address = bvh.getNodeAddress(node_index);

        if (!aabb3_array_intersects_clipping_volume_array(
            float32, node_address,
            planes, planes_offset, plane_count
        )) {
            continue;
        }

        const is_intermediate_node = node_index < binary_node_count;

        if (is_intermediate_node) {
            // is intermediate node

            const left_index = (node_index << 1) + 1;
            const right_index = left_index + 1;

            // left node ends up on top of the stack, which aligns with the desired access sequence
            if (right_index < last_valid_index) {
                stack[stack.pointer++] = right_index;
                // micro-optimization, since we know that right node is valid and left appears before that, left is valid too
                stack[stack.pointer++] = left_index;
            } else if (left_index < last_valid_index) {
                stack[stack.pointer++] = left_index;
            }


        } else {
            // leaf node

            // write to output
            result[result_offset + hit_count] = uint32[node_address + 6];

            hit_count++;
        }

    } while (stack.pointer > stack_top)

    return hit_count;
}