import {
    typedArrayConstructorByInstance
} from "../../../../src/core/collection/array/typed/typedArrayConstructorByInstance.js";
import { FrameRunner } from "../../../../src/engine/graphics/FrameRunner.js";
import html_canvas_to_sampler2d from "../../../../src/engine/graphics/texture/html_canvas_to_sampler2d.js";
import { downloadSampler2DAsPNG } from "../../../../src/engine/graphics/texture/sampler/downloadSamplerAsPNG.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_compute_texel_value_conversion_scale_to_uint8
} from "../../../../src/engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.js";
import sampler2D2Canvas from "../../../../src/engine/graphics/texture/sampler/sampler2d_to_html_canvas.js";
import { sampler2d_transfer_data } from "../../../../src/engine/graphics/texture/sampler/sampler2d_transfer_data.js";
import { MouseEvents } from "../../../../src/engine/input/devices/events/MouseEvents.js";
import { CanvasView } from "../../../../src/view/elements/CanvasView.js";
import EmptyView from "../../../../src/view/elements/EmptyView.js";
import { TypeEditor } from "../TypeEditor.js";

const UPDATE_DELAY = 200;

/**
 *
 * @param {Sampler2D} sampler
 * @param {HTMLCanvasElement} domElement
 */
function draw_sampler(sampler, domElement) {


    let TypedArrayConstructor = typedArrayConstructorByInstance(sampler.data);

    if (TypedArrayConstructor === Uint8Array) {
        // use clamped array to avoid filtering artifacts
        TypedArrayConstructor = Uint8ClampedArray;
    }

    const res = 32;
    const result_sampler = new Sampler2D(new TypedArrayConstructor(sampler.itemSize * res * res), sampler.itemSize, res, res);

    sampler2d_scale(sampler, result_sampler);


    const { scale, offset } = sampler2d_compute_texel_value_conversion_scale_to_uint8(result_sampler);

    sampler2D2Canvas(result_sampler, scale, offset, domElement);

}

/**
 *
 * @param {*} parent
 * @param {HTMLCanvasElement} element
 * @param {FieldDescriptor} field
 */
function enable_drop(parent, element, field) {
    /**
     *
     * @param {DragEvent} ev
     */
    function handleDrop(ev) {
        ev.preventDefault();

        let processed = false;

        /**
         *
         * @param {File} file
         */
        function processFile(file) {
            if (processed) {
                return;
            }

            var img = new Image();
            // URL @ Mozilla, webkitURL @ Chrome
            img.src = (window.webkitURL ? webkitURL : URL).createObjectURL(file);

            // call ctx.drawImage when the image got loaded
            img.onload = function () {
                var canvas = document.createElement("canvas");
                var ctx = canvas.getContext("2d");

                const width = img.width;
                const height = img.height;

                canvas.style.width = `${width}px`;
                canvas.style.height = `${height}px`;

                canvas.width = width;
                canvas.height = height;

                // ctx.drawImage(img, 0, 0);
                ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height); // stretch img to canvas size

                const file_data_sampler = html_canvas_to_sampler2d(canvas);

                /**
                 * @type {Sampler2D}
                 */
                const sampler = field.adapter.read(parent, field.name);

                sampler.resize(width, height, false);

                sampler2d_transfer_data(file_data_sampler, sampler);
            };


            processed = true;
        }

        if (ev.dataTransfer.items) {
            // Use DataTransferItemList interface to access the file(s)
            for (var i = 0; i < ev.dataTransfer.items.length; i++) {
                // If dropped items aren't files, reject them
                if (ev.dataTransfer.items[i].kind === 'file') {
                    var file = ev.dataTransfer.items[i].getAsFile();

                    processFile(file);
                }
            }
        } else {
            // Use DataTransfer interface to access the file(s)
            for (var i = 0; i < ev.dataTransfer.files.length; i++) {
                const file = ev.dataTransfer.files[i];

                processFile(file);
            }
        }
    }

    function handleDragOver(ev) {

        // Prevent default behavior (Prevent file from being opened)
        ev.preventDefault();
    }

    element.addEventListener('dragover', handleDragOver);
    element.addEventListener('drop', handleDrop);
}

export class Sampler2DEditor extends TypeEditor {

    build(parent, field, context) {

        /**
         * @type {Sampler2D}
         */
        const sampler = field.adapter.read(parent, field.name);

        let last_version = -1;
        let last_update_time = 0;
        let last_update_duration = 0;

        const view_container = new EmptyView({
            css:{
                width: "min-content",
                height:"min-content"
            }
        });

        const canvas_view = new CanvasView();
        canvas_view.css({
            background: 'black',
            position: 'relative',
        });

        function draw() {
            const draw_start_time = performance.now();

            draw_sampler(sampler, canvas_view.el);

            last_version = sampler.version;

            const draw_end_time = performance.now();
            last_update_duration = draw_end_time - draw_start_time;

            last_update_time = draw_end_time;
        }


        canvas_view.on.linked.add(try_update);

        function try_update() {
            if (sampler.version !== last_version) {

                const time_now = performance.now();

                if ((time_now - last_update_time) >= UPDATE_DELAY) {
                    draw();
                }
            }
        }

        const frameRunner = new FrameRunner(try_update);

        canvas_view.on.linked.add(frameRunner.startup, frameRunner);
        canvas_view.on.unlinked.add(frameRunner.shutdown, frameRunner);

        //drop target
        const allow_drop = true;
        if (allow_drop) {

            enable_drop(parent, canvas_view.el, field);

        }

        const allow_download = true;
        if (allow_download) {
            canvas_view.el.addEventListener(MouseEvents.Click, () => {
                downloadSampler2DAsPNG(sampler, field.name);
            });
            // add download marker
            view_container.addClass('downloadable');
        }

        view_container.addChild(canvas_view);

        return view_container;
    }
}
