import { BinaryBuffer } from "../../../../core/binary/BinaryBuffer.js";
import { AABB3 } from "../../../../core/geom/3d/aabb/AABB3.js";
import { number_pretty_print } from "../../../../core/primitives/numbers/number_pretty_print.js";
import { Transform } from "../../../ecs/transform/Transform.js";
import { ShadedGeometry } from "../../ecs/mesh-v2/ShadedGeometry.js";
import { build_probes_for_scene } from "./build_probes_for_scene.js";
import { LightProbeVolume } from "./LightProbeVolume.js";
import { LightProbeVolumeSerializationAdapter } from "./serialization/LightProbeVolumeSerializationAdapter.js";

/**
 *
 * @param {Engine} engine
 * @param {string} path
 * @param {LightProbeVolume} [volume]
 * @param {number} [density] only used when building mesh, if loading this parameter is ignored
 * @return {Promise<LightProbeVolume>}
 */
export async function lpv_obtain_storage_cached_volume({
                                                           engine,
                                                           path,
                                                           volume = new LightProbeVolume(),
    density = 500
                                                       }) {

    volume.clear();

    const key = `lpv:${path}`;

    const adapter = new LightProbeVolumeSerializationAdapter();

    if (await engine.storage.promiseContains(key)
        // && false // TODO re-enable
    ) {
        const data = await engine.storage.promiseLoadBinary(key);

        console.log(`LPV data size ${number_pretty_print(data.byteLength)} bytes`);

        const buffer = BinaryBuffer.fromArrayBuffer(data);

        adapter.deserialize(buffer, volume);

        return volume;
    }


    const ecd = engine.entityManager.dataset;

    // build bounding box for the scene
    const mesh_bounds = new AABB3();
    mesh_bounds.setNegativelyInfiniteBounds();

    ecd.traverseEntities([ShadedGeometry, Transform],
        /**
         *
         * @param {ShadedGeometry} sg
         * @param transform
         * @param entity
         */
        (sg, transform, entity) => {

            const box = new AABB3();

            sg.getBoundingBox(box);

            mesh_bounds.union(box);

        });

    await build_probes_for_scene({
        volume,
        engine,
        ecd,
        bounds: mesh_bounds,
        density: density
    });

    const buffer = new BinaryBuffer();

    adapter.serialize(buffer, volume);

    buffer.trim();

    engine.storage.promiseStoreBinary(key, buffer.data)

    return volume;
}