import { Sampler2D } from "../../../graphics/texture/sampler/Sampler2D.js";
import { assert } from "../../../../core/assert.js";
import { bitmap2sampler_gl } from "./bitmap2sampler_gl.js";
import { fastArrayEquals } from "../../../../core/collection/array/fastArrayEquals.js";

/**
 *
 * @type {WeakMap<ImageBitmap, Sampler2D>}
 */
const sampler_cache = new WeakMap();

/**
 *
 * @param {ImageBitmap} bitmap
 * @param {WebGL2RenderingContext} ctx
 * @returns {Sampler2D}
 */
function obtainSampler(bitmap, ctx) {
    // look for materialized data in cache
    const existing_sampler = sampler_cache.get(bitmap);

    if (existing_sampler !== undefined) {
        // found cached data
        return existing_sampler;
    }

    // not found in cache, lets build it

    const width = bitmap.width;
    const height = bitmap.height;

    const sampler = Sampler2D.uint8(4, width, height);

    bitmap2sampler_gl(ctx, sampler, bitmap);

    // cache the result
    sampler_cache.set(bitmap, sampler);

    return sampler;
}

/**
 * Ref holding webgl context, being weak-ref, allows context to be removed when not in use
 * @type {WeakRef<WebGL2RenderingContext>|null}
 */
let ctx_ref = null;

/**
 *
 * @param {number} width
 * @param {number} height
 * @returns {WebGL2RenderingContext}
 */
function obtainCanvasCtx(width, height) {
    assert.lessThanOrEqual(width, 0xFFFF, 'maximum supported size');
    assert.lessThanOrEqual(height, 0xFFFF, 'maximum supported size');

    let gl;

    if (ctx_ref === null || (gl = ctx_ref.deref()) === undefined) {
        const canvas = document.createElement('canvas');

        gl = canvas.getContext("webgl2");
        gl.activeTexture(gl.TEXTURE0);

        const texture = gl.createTexture();

        gl.bindTexture(gl.TEXTURE_2D, texture);

        const framebuffer = gl.createFramebuffer();

        gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);

        ctx_ref = new WeakRef(gl);
    }


    return gl;
}

/**
 *
 * @param {ImageBitmap} bitmap
 * @return {Sampler2D}
 */
export function sampler_from_bitmap(bitmap) {
    const ctx = obtainCanvasCtx(bitmap.width, bitmap.height);

    return obtainSampler(bitmap, ctx);
}

/**
 *
 * @param {ImageBitmap} a
 * @param {ImageBitmap} b
 * @returns {boolean}
 */
export function computeImageBitmapEquality(a, b) {
    if (a === b) {
        // strict equality check, special case
        return true;
    }

    if (a.width !== b.width || a.height !== b.height) {
        // check dimensions
        return false;
    }

    // have to draw both to compare
    const ctx = obtainCanvasCtx(a.width, a.height);

    const a_s = obtainSampler(a, ctx);

    const b_s = obtainSampler(b, ctx);

    return fastArrayEquals(a_s.data, b_s.data);
}
