import { ParameterLookupTable } from "../../../particles/particular/engine/parameter/ParameterLookupTable.js";
import { MouseEvents } from "../../../../input/devices/events/MouseEvents.js";
import { readPositionFromMouseEvent } from "../../../../input/devices/PointerDevice.js";
import Vector2 from "../../../../../core/geom/Vector2.js";
import { VisualTip } from "../../../../../view/tooltip/VisualTip.js";
import Rectangle from "../../../../../core/geom/2d/Rectangle.js";
import LabelView from "../../../../../view/common/LabelView.js";
import { CanvasView } from "../../../../../view/elements/CanvasView.js";
import EmptyView from "../../../../../view/elements/EmptyView.js";
import { Color } from "../../../../../core/color/Color.js";
import { halton_sequence } from "../../../../../core/math/statistics/halton_sequence.js";
import { lerp } from "../../../../../core/math/lerp.js";


/**
 *
 * @param {TooltipManager} tooltips
 * @param {View} view
 * @param {LightManager} lm
 */
function make_tooltips({
                           tooltips,
                           view,
                           lm
                       }) {

    let tip = null;

    view.css({ pointerEvents: 'auto' });


    /**
     *
     * @param {number} x
     * @param {number} y
     * @param {number} z
     */
    function build_cluster_tip(x, y, z) {
        const image = lm.getTextureClusters().image;

        const lookup_image = lm.getTextureLookup().image;

        const light_data_size = lm.__light_data.size;

        const texel_index = image.width * image.height * z + image.width * y + x;

        // RGB format
        const texel_address = texel_index * 3;

        const lookup_index = image.data[texel_address + 0];
        const light_count = image.data[texel_address + 1];


        const vContainer = new EmptyView();
        vContainer.css({
            display: 'flex',
            flexDirection: 'column',
            padding: '2px',
            borderColor: 'rgba(255,255,255,0.1)',
            borderWidth: '1px',
            borderStyle: 'solid'
        });

        vContainer.addChild(new LabelView(`${x}:${y}:${z}`));

        for (let i = 0; i < light_count; i++) {
            const lookup_offset = lookup_index + i;

            const light_descriptor = lookup_image.data[lookup_offset];

            const light_type = light_descriptor & 0x3;

            const light_address = light_descriptor >> 2;

            const light_address_normalized = light_address / light_data_size;

            const vLight = new LabelView(`${light_type}:${light_address}`);

            const hue = light_address_normalized;
            const color = new Color();

            const saturation_phase = halton_sequence(4, Math.floor(light_address / 4) % 4)

            color.setHSV(hue, lerp(0.4, 0.7, saturation_phase), 1);

            vLight.css({
                color: color.toHex(),
                textShadow: '0 0 1px black'
            });

            vContainer.addChild(vLight);
        }

        return vContainer;
    }

    function clear_tip() {

        if (tip !== null) {
            tooltips.remove(tip);
            tip = null;
        }

    }


    const click_handler = (mouseEvent) => {

        console.log('Click');

        clear_tip();

        const resolution = lm.getResolution();

        const p = new Vector2();

        readPositionFromMouseEvent(p, mouseEvent, view.el);

        const tile_w = view.size.x / resolution.x;
        const tile_h = view.size.y / resolution.y;

        const tile_x = Math.floor(p.x / tile_w);
        const tile_y = Math.floor(p.y / tile_h);


        tip = new VisualTip(new Rectangle(
            tile_x * tile_w, tile_y * tile_h, tile_w, tile_h
        ), () => {

            const vContainer = new EmptyView();

            vContainer.css({
                display: 'flex',
                flexDirection: 'row'
            });

            for (let i = 0; i < resolution.z; i++) {
                const vCluster = build_cluster_tip((resolution.x - 1) - tile_x, (resolution.y - 1) - tile_y, i);

                vContainer.addChild(vCluster);
            }

            return vContainer;

        });

        tooltips.add(tip);

    };

    view.on.linked.add(() => {
        view.el.addEventListener(MouseEvents.Click, click_handler);
    });

    view.on.unlinked.add(() => {
        view.el.removeEventListener(MouseEvents.Click, click_handler);

        clear_tip();
    });

}

/**
 *
 * @param {number} width
 * @param {number} height
 * @param {LightManager} lm
 * @param {boolean} [heatmap]
 * @param {TooltipManager} [tooltips]
 * @returns {{domElement: HTMLCanvasElement, view:View}}
 */
export function createScreenGrid({
                                     width,
                                     height,
                                     lm,
                                     heatmap = true,
                                     tooltips
                                 }) {

    const heatmap_lut = new ParameterLookupTable(4);
    heatmap_lut.write([
        0, 0, 0, 255,
        0, 0, 255, 255,
        0, 179, 179, 255,
        0, 255, 0, 255,
        255, 255, 0, 255,
        255, 5, 5, 255
    ]);
    heatmap_lut.computeUniformPositions();

    const canvasView = new CanvasView();
    canvasView.size.set(width, height);

    const canvasElement = canvasView.el;

    const ctx = canvasView.context2d;


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

    canvasElement.style.position = 'absolute';
    canvasElement.style.left = '0';
    canvasElement.style.top = '0';
    canvasElement.style.zIndex = '1';

    // canvasElement.style.mixBlendMode = 'difference';

    if (tooltips !== undefined) {
        make_tooltips({
            lm,
            tooltips,
            width,
            height,
            view: canvasView
        });
    } else {

        canvasElement.style.pointerEvents = 'none';
    }


    function draw_grid() {

        ctx.strokeStyle = "rgba(255,255,255,0.2)";
        ctx.lineWidth = 1;

        ctx.beginPath();

        const x_divisions = lm.getResolution().x;
        const y_divisions = lm.getResolution().y;

        const x_spacing = width / x_divisions;
        const y_spacing = height / y_divisions;

        for (let i = 0; i < x_divisions; i++) {
            ctx.moveTo(i * x_spacing, 0);
            ctx.lineTo(i * x_spacing, height);
        }

        ctx.stroke();
        ctx.beginPath();

        for (let i = 0; i < y_divisions; i++) {
            ctx.moveTo(0, i * y_spacing);
            ctx.lineTo(width, i * y_spacing);
        }

        ctx.stroke();
    }

    function draw_cluster() {
        const textureTiles = lm.getTextureClusters();

        const image = textureTiles.image;

        const data = image.data;

        const resolution = lm.getResolution();

        const x_divisions = resolution.x;
        const y_divisions = resolution.y;

        const x_spacing = width / x_divisions;
        const y_spacing = height / y_divisions;

        ctx.font = '10px Tahoma';
        ctx.lineWidth = 1;

        const color = [];

        for (let i_x = 0; i_x < resolution.x + 1; i_x++) {
            for (let i_y = 0; i_y < resolution.y + 1; i_y++) {

                let found_matches = 0;
                for (let i_z = 0; i_z < resolution.z + 1; i_z++) {
                    const index = i_z * resolution.x * resolution.y + (resolution.y - 1 - i_y) * resolution.x + (resolution.x - 1 - i_x);

                    const address = index * 3;

                    const point_light_count = data[address + 1];

                    if (point_light_count > 0) {
                        found_matches++;
                    }
                }

                const z_light_saturation = found_matches / resolution.z;

                heatmap_lut.sample(z_light_saturation, color)

                const p_x = i_x * x_spacing;
                const p_y = i_y * y_spacing;

                ctx.fillStyle = 'white';
                ctx.strokeStyle = `rgb(${color[0]},${color[1]},${color[2]})`;
                ctx.strokeText(found_matches, p_x, p_y + 10);
                ctx.fillText(found_matches, p_x, p_y + 10);

                if (heatmap) {

                    ctx.fillStyle = `rgba(${color[0]},${color[1]},${color[2]},0.2)`;
                    ctx.fillRect(p_x, p_y, x_spacing, y_spacing);
                }

            }
        }
    }

    function update() {
        ctx.clearRect(0, 0, width, height);

        draw_grid();

        draw_cluster();
    }

    update();

    canvasView.on.linked.add(update);

    return {
        update,
        domElement: canvasElement,
        view: canvasView
    };
}
