import Signal from "../../../../src/core/events/signal/Signal.js";
import Vector2 from "../../../../src/core/geom/Vector2.js";
import ObservedValue from "../../../../src/core/model/ObservedValue.js";
import { TerrainLayer } from "../../../../src/engine/ecs/terrain/ecs/layers/TerrainLayer.js";
import CheckersTextureURI from "../../../../src/engine/graphics/texture/CheckersTextureURI.js";
import { sampler2d_scale } from "../../../../src/engine/graphics/texture/sampler/resize/sampler2d_scale.js";
import { Sampler2D } from "../../../../src/engine/graphics/texture/sampler/Sampler2D.js";
import sampler2d_to_html_canvas from "../../../../src/engine/graphics/texture/sampler/sampler2d_to_html_canvas.js";
import LabelView from "../../../../src/view/common/LabelView.js";
import { NativeListController } from "../../../../src/view/controller/controls/NativeListController.js";
import Vector2Control from "../../../../src/view/controller/controls/Vector2Control.js";
import { CanvasView } from "../../../../src/view/elements/CanvasView.js";
import EmptyView from "../../../../src/view/elements/EmptyView.js";
import GroupView from "../../../../src/view/elements/Group.js";
import View from "../../../../src/view/View.js";
import DatGuiController from "./DatGuiController.js";

class LayersController extends View {
    /**
     *
     * @param {Terrain} terrain
     * @param {TerrainLayers} layers
     * @param {AssetManager} assetManager
     */
    constructor({ terrain, layers, assetManager }) {
        super();

        this.el = document.createElement('div');
        this.addClass('ui-terrain-layers-controller-view');


        function updateLayers() {

            terrain.layers.buildTexture();
            terrain.layers.writeAllLayersDataIntoTexture();

            terrain.updateMaterial();
        }

        const updateBus = new Signal();

        this.bindSignal(layers.layers.on.added, () => {
            terrain.splat.addWeightLayer();
        });

        this.bindSignal(layers.layers.on.removed, (layer, index) => {
            terrain.splat.removeWeightLayer(index);
            updateLayers();
        });

        this.addChild(
            new NativeListController({
                model: layers.layers,
                elementFactory() {
                    const layer = new TerrainLayer();

                    layer.textureDiffuseURL = CheckersTextureURI;
                    layer.size.set(1, 1);

                    layer.loadTextureData(assetManager)
                        .then(() => {

                            updateLayers();

                            updateBus.send1(layer);
                        });

                    return layer;
                },
                /**
                 *
                 * @param {TerrainLayer} layer
                 * @return {View}
                 */
                elementViewFactory(layer) {
                    const v = new EmptyView();

                    v.bindSignal(updateBus, (l) => {
                        if (l === layer) {
                            update();
                        }
                    });

                    v.addClass('ui-terrain-layer-controller-view');


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

                    const t = Sampler2D.uint8(layer.diffuse.itemSize, 64, 64);


                    function update() {

                        sampler2d_scale(layer.diffuse, t);

                        sampler2d_to_html_canvas(t, 1, 0, vCanvas.el);
                    }

                    update();


                    v.addChild(vCanvas);

                    const vURL = new EmptyView({ classList: ['url'], tag: 'input' });
                    const elValue = vURL.el;

                    elValue.setAttribute('type', 'text');
                    elValue.value = layer.textureDiffuseURL;


                    elValue.addEventListener('input', () => {
                        const v = elValue.value;

                        layer.textureDiffuseURL = v;

                        layer.loadTextureData(assetManager).then(() => {
                            update();

                            const index = layers.layers.indexOf(layer);

                            layers.writeLayerDataIntoTexture(index);
                        });
                    });

                    const vSize = new Vector2Control();
                    vSize.model.set(layer.size);

                    v.bindSignal(layer.size.onChanged, terrain.updateMaterial, terrain);

                    const groupView = new GroupView();
                    groupView.add(new LabelView('size'));
                    groupView.add(vSize);

                    v.addChild(groupView);

                    v.addChild(vURL);

                    return v;
                }
            })
        );
    }
}

export class TerrainController extends View {
    /**
     *
     * @param {AssetManager} assetManager
     */
    constructor(assetManager) {
        super();

        this.el = document.createElement('div');

        this.model = new ObservedValue(null);

        const self = this;

        /**
         *
         * @param {Terrain} model
         */
        function setModel(model) {

            self.removeAllChildren();
            const controller = new DatGuiController();
            self.addChild(controller);

            if (model !== null) {
                controller.addAction(() => {
                    model.__tiles.rebuild();
                }, 'Rebuild');

                controller.add(model, 'size', { step: 1 });
                controller.add(model, 'resolution').step(1);
                controller.add(model, 'gridScale').step(1).name('Gird Size');

                const proxy = {
                    heightResolution: new Vector2(model.samplerHeight.width, model.samplerHeight.height),
                    weightResolution: new Vector2(model.splat.size.x, model.splat.size.y),
                    layerResolution: new Vector2(model.layers.resolution.x, model.layers.resolution.y),
                };

                proxy.heightResolution.onChanged.add((x, y) => {
                    model.samplerHeight.resize(x, y);
                });

                proxy.weightResolution.onChanged.add((x, y) => {
                    model.splat.resize(x, y, model.splat.depth);
                });

                proxy.layerResolution.onChanged.add((x, y) => {
                    model.layers.resolution.set(x, y);

                    model.layers.buildTexture();
                    model.layers.writeAllLayersDataIntoTexture();
                });

                controller.add(proxy, 'heightResolution', { step: 1 });
                controller.add(proxy, 'weightResolution', { step: 1 });
                controller.add(proxy, 'layerResolution', { step: 1 });

                if (model.preview.url === null) {
                    model.preview.url = '';
                }

                controller.add(model.preview, 'url').name('preview url');
                controller.add(model.preview, 'offset');
                controller.add(model.preview, 'scale');

                self.addChild(new LayersController({ terrain: model, layers: model.layers, assetManager }));
            }
        }

        this.model.onChanged.add(setModel);
    }
}
