import { ClampToEdgeWrapping, DataTexture, FloatType, NearestFilter, OctahedronBufferGeometry, RedFormat } from "three";
import { TransformControls } from "../../../../../../../editor/tools/v2/TransformControls.js";
import Entity from "../../../../../ecs/Entity.js";
import { Transform } from "../../../../../ecs/transform/Transform.js";
import { ShadedGeometry } from "../../../../ecs/mesh-v2/ShadedGeometry.js";
import { PathTracedScene } from "../../../path_tracer/PathTracedScene.js";
import { populate_path_traced_scene_from_ecd } from "../../../path_tracer/populate_path_traced_scene_from_ecd.js";
import { bake_octahedral_depth_map } from "./bake_octahedral_depth_map.js";
import { OctahedralDepthVisualizationMaterial } from "./shader/OctahedralDepthVisualizationMaterial.js";

export class OctahedralDepthDebuggerWidget {

    /**
     * @type {PathTracedScene}
     */
    #scene = new PathTracedScene();

    #resolution = 64;

    #texture = new DataTexture(
        new Float32Array(this.#resolution * this.#resolution),
        this.#resolution,
        this.#resolution,
        RedFormat,
        FloatType
    );

    #entity = new Entity();

    constructor() {
        this.#texture.generateMipmaps = false;

        this.#texture.magFilter = NearestFilter;
        this.#texture.minFilter = NearestFilter;

        this.#texture.wrapT = ClampToEdgeWrapping;
        this.#texture.wrapS = ClampToEdgeWrapping;

        this.#texture.flipY = false;


        const material = new OctahedralDepthVisualizationMaterial();

        material.texture = this.#texture;
        material.scale = 10;

        const transform = new Transform();
        this.#entity.add(transform);
        this.#entity.add(ShadedGeometry.from(new OctahedronBufferGeometry(1, 4), material));


        transform.position.onChanged.add(this.update, this);

    }

    update() {

        console.time('depth build');
        bake_octahedral_depth_map(
            this.#texture.image.data, 0,
            this.#scene,
            this.#entity.getComponentSafe(Transform).position, 0,
            this.#resolution, 100
        );
        console.timeEnd('depth build');

        this.#texture.needsUpdate = true;
    }

    /**
     *
     * @returns {Entity}
     */
    get entity() {
        return this.#entity;
    }

    /**
     *
     * @param {EntityComponentDataset} ecd
     * @param {Engine} engine
     */
    build(ecd, engine) {

        populate_path_traced_scene_from_ecd(ecd, this.#scene);

        this.update();

        this.#entity.build(ecd);


        const gizmo = new TransformControls(engine.graphics.camera, engine.graphics.domElement, true);

        gizmo.build(ecd);


        gizmo.attach(this.#entity.id);
    }

}