import { assert } from "../../../../../core/assert.js";
import LabelView from "../../../../../view/common/LabelView.js";
import { CSS_ABSOLUTE_POSITIONING } from "../../../../../view/CSS_ABSOLUTE_POSITIONING.js";
import EmptyView from "../../../../../view/elements/EmptyView.js";
import { decompose_finger_print } from "../tile/decompose_finger_print.js";
import { tile_address_to_finger_print } from "../tile/tile_address_to_finger_print.js";

class TextureLODView extends EmptyView {

    /**
     *
     * @type {View[]}
     */
    #tiles = [];

    #resolution = [1, 1];

    constructor({
                    resolution = [1, 1],
                    tile_size = 8
                }) {
        super({ css: CSS_ABSOLUTE_POSITIONING });

        this.css({
            background: "rgba(255,255,255,0.05)"
        });

        this.#resolution = resolution;

        const width = resolution[0];
        const height = resolution[1];

        assert.isNonNegativeInteger(width, 'width');
        assert.isNonNegativeInteger(height, 'height');

        for (let j = 0; j < height; j++) {
            for (let i = 0; i < width; i++) {
                const tileView = new EmptyView({ css: CSS_ABSOLUTE_POSITIONING });

                // const flipped_y = height - j - 1;
                tileView.position.set(i * tile_size, j * tile_size);
                // tileView.position.set(i * tile_size, flipped_y * tile_size);
                tileView.size.set(tile_size, tile_size);

                this.clearTile(tileView);

                this.#tiles.push(tileView)

                this.addChild(tileView);
            }
        }

        this.size.set(width * tile_size, height * tile_size);


        const label = new LabelView(`${width} x ${height}`, {
            css: {
                ...CSS_ABSOLUTE_POSITIONING,
                color: '#FFFFFF',
                textShadow: '0 0 2px black',
                whiteSpace: "pre"
            }
        });

        label.position.set(this.size.x + 4, (this.size.y - 20) * 0.5);

        this.addChild(label);
    }

    clear() {
        const resolution = this.#resolution;
        const count = resolution[0] * resolution[1];
        for (let i = 0; i < count; i++) {

            const view = this.#tiles[i];

            this.clearTile(view);
        }
    }

    /**
     *
     * @param {View} view
     */
    clearTile(view) {

        view.css({
            background: "none"
        });

        view.visible = false;
    }

    getTile(x, y) {
        assert.isNonNegativeInteger(x, 'x');
        assert.isNonNegativeInteger(y, 'y');

        const resolution = this.#resolution;

        // assert.lessThan(x, resolution[0]);
        // assert.lessThan(y, resolution[1]);

        const width = resolution[0];

        const view = this.#tiles[x + width * y];

        if (view === undefined) {
            debugger
        }

        return view;

    }

}

export class UsagePyramidDebugView extends EmptyView {
    #levels = [];
    #resolution = [1, 1];
    #tile_size = 0;

    #used_set = [];
    #used_set_size = 0;

    #image_url = null

    setImageURL(url) {
        this.#image_url = url;

        this.#applyImageURL();
    }

    #applyImageURL() {

        const background = {
            backgroundImage: this.#image_url === null ? "none" : `url(${this.#image_url})`,
            backgroundSize: "contain"
        };

        this.#levels.forEach(l => {

            l.css(background);

        });
    }

    setTextureParameters(resolution, tile_size) {
        if (this.#resolution[0] === resolution && this.#resolution[1] === resolution && this.#tile_size === tile_size) {
            return;
        }

        this.#tile_size = tile_size;
        this.#resolution = [resolution, resolution];

        this.#levels.splice(0, this.#levels.length);
        this.removeAllChildren();

        let size = resolution / tile_size;

        assert.isNonNegativeInteger(size, 'size');

        while (size > 0) {
            const lod = new TextureLODView({
                resolution: [size, size],
            });

            lod.css({
                border: "1px solid rgba(0,0,0,0.7)"
            });

            this.#levels.push(lod);

            this.addChild(lod);

            size >>>= 1;
        }

        this.#levels.reverse();

        let y = 0;
        for (let i = 0; i < this.#levels.length; i++) {
            const level = this.#levels[i];

            level.position.set(2, y);

            y += level.size.y + 4;
        }

        this.#applyImageURL();
    }

    /**
     *
     * @param {VirtualTextureUsage} usage
     */
    set usage(usage) {

        for (let i = 0; i < this.#used_set_size; i++) {
            const finger_print = this.#used_set[i];

            const { mip, x, y } = decompose_finger_print(finger_print);

            const mipView = this.#levels[mip];

            const tile = mipView.getTile(x, y);

            mipView.clearTile(tile);
        }
        this.#used_set_size = 0;


        const occupancy = usage.occupancy;
        const occupancyCount = usage.occupancy_count;

        for (let i = 0; i < occupancyCount; i++) {
            const occupancy_index = occupancy[i];
            const fingerPrint = tile_address_to_finger_print(occupancy_index);

            const count = usage.getCountByFingerprint(fingerPrint);

            if (count <= 0) {
                continue;
            }

            const { mip, x, y } = decompose_finger_print(fingerPrint);


            const mipView = this.#levels[mip];

            const tile = mipView.getTile(x, y);

            tile.css({
                background: "rgba(255,0,0,0.8)"
            });

            tile.visible = true;

            this.#used_set[this.#used_set_size] = fingerPrint;
            this.#used_set_size++;
        }

    }
}