import {
    AmbientLight,
    Mesh,
    MeshStandardMaterial,
    OctahedronBufferGeometry,
    PerspectiveCamera,
    Scene,
    TextureLoader,
    Vector3,
    WebGLRenderer
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { makeSolidArrowGeometry } from "../../../../../../editor/process/symbolic/makeSolidArrowGeometry.js";
import { AssetManager } from "../../../../../engine/asset/AssetManager.js";
import { ImageRGBADataLoader } from "../../../../../engine/asset/loaders/image/ImageRGBADataLoader.js";
import sampler2D2Canvas from "../../../../../engine/graphics/texture/sampler/sampler2d_to_html_canvas.js";
import { MouseEvents } from "../../../../../engine/input/devices/events/MouseEvents.js";
import { CSS_ABSOLUTE_POSITIONING } from "../../../../../view/CSS_ABSOLUTE_POSITIONING.js";
import { CanvasView } from "../../../../../view/elements/CanvasView.js";
import EmptyView from "../../../../../view/elements/EmptyView.js";
import { Color } from "../../../../color/Color.js";
import { decode_octahedron_to_unit } from "./decode_octahedron_to_unit.js";

const renderer = new WebGLRenderer();

const scene = new Scene();

const camera = new PerspectiveCamera();


function onWindowResize() {


    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);

}


onWindowResize();


window.addEventListener('resize', onWindowResize, false);

const vContainer = new EmptyView({
    css: {
        ...CSS_ABSOLUTE_POSITIONING
    }
});

const vCanvas = new CanvasView();
vCanvas.size.set(512, 512);

vContainer.addChild(vCanvas);

const assetManager = new AssetManager();


function placeMarker(u, v, color = "rgba(255,0,0,1)") {

    const direciton_0 = new Vector3(0, 1, 0);

    const encoded = [];
    decode_octahedron_to_unit(encoded, 0, u, v);

    direciton_0.fromArray(encoded);

    const arrow_mesh_0 = new Mesh(
        makeSolidArrowGeometry(),
        new MeshStandardMaterial({
            color: color
        })
    );

    arrow_mesh_0.position.copy(direciton_0).multiplyScalar(1);

    arrow_mesh_0.lookAt(
        arrow_mesh_0.position.clone().add(direciton_0)
    );

    scene.add(arrow_mesh_0);
}

function canvasPlaceDot(u, v, color = "rgba(255,0,0,1)") {


    const marker_0 = new EmptyView({
        css: {
            ...CSS_ABSOLUTE_POSITIONING,
            borderRadius: "5px",
            width: "5px",
            height: "5px",
            background: color,
            boxShadow: "0 0 4px 2px black"
        }
    });

    marker_0.position.set(u * vCanvas.size.x, v * vCanvas.size.y);

    vContainer.addChild(marker_0);
}

async function init_debug() {

    const ctx2d = vCanvas.context2d;

    ctx2d.fillStyle = 'rgba(0,0,0,0.5)';
    ctx2d.fillRect(0, 0, vCanvas.size.x, vCanvas.size.y);

    const asset = await assetManager.promise("data/textures/utility/uv_map_reference.png", 'image');

    /**
     *
     * @type {Sampler2D}
     */
    const sampler = asset.create();

    sampler2D2Canvas(sampler, 1, 0, vCanvas.el);


    const marker_0 = new EmptyView({
        css: {
            ...CSS_ABSOLUTE_POSITIONING,
            borderRadius: "5px",
            width: "5px",
            height: "5px",
            background: "rgba(255,0,0,1)",
            boxShadow: "0 0 4px 2px black"
        }
    });

    function make_grid(RESOLUTION = 16) {

        const color = new Color();

        const sample_color = [255, 255, 255];

        const pixel_size = 1 / RESOLUTION;

        for (let i = 0; i < RESOLUTION; i++) {

            for (let j = 0; j < RESOLUTION; j++) {

                const u = (i) / (RESOLUTION);
                const v = (j) / (RESOLUTION);

                sampler.sampleBicubicUV(u + pixel_size * 0.1, v + pixel_size * 0.1, sample_color);

                color.setRGBUint8(sample_color[0], sample_color[1], sample_color[2]);

                const color_string = color.toCssRGBAString();

                const centered_u = u + pixel_size * 0.5;
                const centered_v = v + pixel_size * 0.5;

                canvasPlaceDot(centered_u, centered_v, color_string);
                placeMarker(centered_u * 2 - 1, centered_v * 2 - 1, color_string);
            }

        }
    }

    make_grid(16);

    vContainer.addChild(marker_0);

    vCanvas.el.addEventListener(MouseEvents.Down,
        /**
         *
         * @param {MouseEvent} mouseEvent
         */
        (mouseEvent) => {

            const x = mouseEvent.clientX;
            const y = mouseEvent.clientY;
            marker_0.position.set(x, y);
        });
}

function animate() {
    requestAnimationFrame(animate);


    renderer.render(scene, camera);
}

async function init() {
    await assetManager.registerLoader('image', new ImageRGBADataLoader());

    assetManager.startup();

    document.body.appendChild(renderer.domElement);
    document.body.appendChild(vContainer.el);
    vContainer.link();

    await init_debug();

    // camera

    camera.position.set(0, 0, -3);
    camera.lookAt(0, 0, 0);

    // meshes

    const geometry = new OctahedronBufferGeometry(1, 3);

    const texture = new TextureLoader().load("data/textures/utility/uv_map_reference.png");
    texture.flipY = true;

    const mesh = new Mesh(geometry, new MeshStandardMaterial({
        map: texture
    }));

    scene.add(mesh);

    // lights

    scene.add(new AmbientLight(0x333333));

    const controls = new OrbitControls(camera, document.body);

    animate();
}

init();
