//
import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
import { aabb3_array_intersects_frustum_degree } from "../../../geom/3d/aabb/aabb3_array_intersects_frustum_degree.js";
import { NULL_NODE } from "../BVH.js";
import { bvh_collect_user_data } from "./bvh_collect_user_data.js";

const stack = SCRATCH_UINT32_TRAVERSAL_STACK;

const scratch_aabb = new Float32Array(6);

/**
 *
 * @param {number[]} result
 * @param {number} result_offset
 * @param {BVH} bvh
 * @param {number[]|Float32Array} frustum
 */
export function bvh_query_user_data_overlaps_frustum(
    result,
    result_offset,
    bvh,
    frustum
) {
    const root = bvh.root;

    if (root === NULL_NODE) {
        return 0;
    }

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

    stack[stack_top] = root;

    let result_cursor = result_offset;

    while (stack.pointer > stack_top) {
        stack.pointer--;

        /**
         *
         * @type {number}
         */
        const node = stack[stack.pointer];

        // test node against the ray
        bvh.node_get_aabb(node, scratch_aabb);
        const intersection = aabb3_array_intersects_frustum_degree(scratch_aabb,0, frustum);

        if (intersection === 0) {
            // fully outside
            continue;
        }

        const node_is_leaf = bvh.node_is_leaf(node);

        if (node_is_leaf) {
            // leaf node
            result[result_cursor++] = bvh.node_get_user_data(node);

        } else if (intersection === 2) {
            // fully inside, fast collection path
            result_cursor += bvh_collect_user_data(result, result_cursor, bvh, node);
        } else {
            // partially inside
            // read in-order
            const child1 = bvh.node_get_child1(node);
            const child2 = bvh.node_get_child2(node);

            // write to stack in reverse order, so that fist child ends up being visited first
            stack[stack.pointer++] = child1;
            stack[stack.pointer++] = child2;
        }
    }

    // drop stack frame

    return result_cursor - result_offset;
}
