import { assert } from "../../../core/assert.js";
import {
    bvh_query_user_data_overlaps_frustum
} from "../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_frustum.js";

/**
 * Assumes that BVH stored entity IDs
 * @param {EntityManager} em
 * @param {BVH} bvh
 * @param {function(Object3D[],number,number,EntityComponentDataset)} extract
 * @param {*} [extract_context]
 * @returns {(function(Object3D[], number, CameraView): number)|*}
 */
export function make_bvh_visibility_builder(em, bvh, extract, extract_context) {
    assert.defined(em, 'em');
    assert.defined(bvh, 'bvh');
    assert.isFunction(extract, 'extract');

    const scratch_array = [];

    /**
     *
     * @param {THREE.Object3D[]} destination
     * @param {number} destination_offset
     * @param {CameraView} view
     * @returns {number} Number of records added to destination
     */
    function compute(destination, destination_offset, view) {

        if (em === null) {
            return 0;
        }

        const dataset = em.dataset;

        if (dataset === null) {
            return 0;
        }

        const matches = bvh_query_user_data_overlaps_frustum(
            scratch_array, 0,
            bvh, view.frustum
        );

        let additions = 0;

        for (let i = 0; i < matches; i++) {
            const entity = scratch_array[i];

            const offset = destination_offset + additions;

            const elements_from_entity = extract.call(extract_context, destination, offset, entity, dataset);

            assert.isNonNegativeInteger(elements_from_entity, 'additions');

            additions += elements_from_entity;
        }

        return additions;
    }

    return compute;

}