import { Color } from "../../../src/core/color/Color.js";
import Vector1 from "../../../src/core/geom/Vector1.js";
import Vector2 from "../../../src/core/geom/Vector2.js";
import { max2 } from "../../../src/core/math/max2.js";
import ObservedString from "../../../src/core/model/ObservedString.js";
import { GameAssetType } from "../../../src/engine/asset/GameAssetType.js";
import { pick } from "../../../src/engine/ecs/grid/pick.js";
import { obtainTerrain } from "../../../src/engine/ecs/terrain/util/obtainTerrain.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 Tool from "../engine/Tool.js";

export class TerrainPaintTool extends Tool {
    constructor() {
        super();

        this.name = 'paint-terrain';

        const marker = Sampler2D.uint8(4, 1, 1);

        marker.data.fill(255);

        this.settings.markerColor = new Color(0, 1, 0.8);
        this.settings.markerOpacity = new Vector1(1);

        this.settings.marker = marker;
        this.settings.brushSize = 5;
        this.settings.brushStrength = 1;
        this.settings.brushURL = new ObservedString("data/textures/particle/UETools/x64/Circle_04.png");

        this.__brushPosition = new Vector2();

        this.__brushImage = document.createElement('canvas');

        this.__paint_debt = 0;
        this.__paint_pending = false;
    }

    /**
     *
     * @param {number} timeDelta
     */
    async paint(timeDelta) {

    }

    /**
     *
     * @param {number} timeDelta
     */
    update(timeDelta) {
        this.updateBrushPosition();
        this.updateOverlay();

        if (this.isRunning()) {

            this.__paint_debt += timeDelta;

            if (this.__paint_pending) {
                return;
            }

            this.__paint_pending = true;

            const paint_promise = this.paint(timeDelta);
            this.__paint_debt = 0;

            paint_promise.finally(() => {
                this.__paint_pending = false;
            });
        }

    }

    updateBrushImage() {
        /**
         *
         * @type {Sampler2D}
         */
        const marker = this.settings.marker;

        const temp = new Sampler2D(new Uint8ClampedArray(marker.data), marker.itemSize, marker.width, marker.height);

        const markerColor = this.settings.markerColor;
        const markerAlpha = this.settings.markerOpacity.getValue();

        const brushData = temp.data;

        //apply tint
        for (let y = 0; y < temp.height; y++) {
            const lineAddress = y * temp.itemSize * temp.width;

            for (let x = 0; x < temp.width; x++) {

                const address = lineAddress + x * temp.itemSize;

                brushData[address] = brushData[address] * markerColor.r;
                brushData[address + 1] = brushData[address + 1] * markerColor.g;
                brushData[address + 2] = brushData[address + 2] * markerColor.b;
                brushData[address + 3] = brushData[address + 3] * markerAlpha;
            }
        }

        const brushImage = this.__brushImage;

        sampler2d_to_html_canvas(temp, 1, 0, brushImage);

    }

    updateBrushPosition() {

        const p = new Vector2(0, 0);
        const engine = this.engine;

        engine.gameView.positionGlobalToLocal(engine.devices.pointer.position, p);

        pick(p.x, p.y, engine.graphics, this.terrain, (gridPosition) => {

            this.__brushPosition.set(gridPosition.x, gridPosition.y);

        });
    }

    updateOverlay() {

        const terrain = this.terrain;

        const overlay = terrain.overlay;

        overlay.clear();

        const dx = overlay.size.x / terrain.size.x;
        const dy = overlay.size.y / terrain.size.y;

        const overlayPositionX = this.__brushPosition.x * dx;
        const overlayPositionY = this.__brushPosition.y * dy;

        const brushSize = this.settings.brushSize;

        const brushRadius = brushSize / 2;

        const brushSizeX = brushRadius * dx;
        const brushSizeY = brushRadius * dy;


        overlay.paintImage(this.__brushImage, overlayPositionX - brushSizeX, overlayPositionY - brushSizeY, brushSize * dx, brushSize * dy);
    }

    /**
     *
     * @param {Vector3} delta
     * @private
     */
    __handleMouseWheel(delta) {

        const settings = this.settings;

        const brushSize = settings.brushSize;

        settings.brushSize = max2(1, brushSize + delta.y);

        // this.updateBrushImage();
        this.updateOverlay();

    }

    initialize() {
        super.initialize();

        const engine = this.engine;
        const editor = this.editor;

        this.__paint_debt = 0;

        this.terrain = obtainTerrain(engine.entityManager.dataset, (t, entity) => {
            this.terrainEntity = entity;
        });

        const overlay = this.terrain.overlay;

        overlay.push();

        overlay.size.set(this.terrain.size.x * 16, this.terrain.size.y * 16);
        overlay.borderWidth.set(0);
        overlay.tileImage.set("data/textures/utility/white_pixel.png");

        engine.assetManager.promise('data/textures/particle/UETools/x64/Circle_04.png', GameAssetType.Image)
            .then(asset => {
                const image = asset.create();

                this.settings.marker = new Sampler2D(image.data, 4, image.width, image.height);

                this.updateBrushImage();
            });

        this.updateBrushImage();

        engine.devices.pointer.on.wheel.add(this.__handleMouseWheel, this);
    }

    finalize() {
        super.finalize();


        this.terrain.overlay.pop();


        engine.devices.pointer.on.wheel.remove(this.__handleMouseWheel, this);
    }

}
