import { assert } from "../../../../core/assert.js";
import ImageFilter from "../../filter/ImageFilter.js";
import { sampler2d_flipY_in_place } from "../../filter/sampler2d_flipY_in_place.js";
import CopyShader from "../../postprocess/threejs/shaders/CopyShader.js";
import { WebGLRendererPool } from "../../render/RendererPool.js";

import { canvasDataToSampler } from "../canvasDataToSampler.js";
import { formatToChannelCount } from "../formatToChannelCount.js";
import { sampler2d_scale } from "./resize/sampler2d_scale.js";
import { Sampler2D } from "./Sampler2D.js";
import { sampler2d_ensure_uint8_RGBA } from "./sampler2d_ensure_uint8_RGBA.js";


const DEFAULT_TEXTURE_WIDTH = 512;
const DEFAULT_TEXTURE_HEIGHT = 512;

/**
 *
 * @param {THREE.DataTexture} texture
 * @param {number} channel_count
 * @param {number} _width
 * @param {number} _height
 * @returns {Sampler2D}
 */
function data_texture_to_sampler(texture, channel_count, _width, _height) {
    const source = new Sampler2D(texture.image.data, channel_count, texture.image.width, texture.image.height);

    let converted = sampler2d_ensure_uint8_RGBA(source);

    if (converted.width !== _width || converted.height !== _height) {
        const target = Sampler2D.uint8(4, _width, _height);

        sampler2d_scale(converted, target);

        converted = target;
    }
    return converted;
}

/**
 *
 * @param {THREE.Texture} texture
 * @param {number} channel_count
 * @param {number} _width
 * @param {number} _height
 * @returns {Sampler2D}
 */
function html_image_texture_to_sampler(texture, channel_count, _width, _height) {
    /**
     *
     * @type {Image}
     */
    const img = texture.image;

    assert.isInstanceOf(img, Image, 'texture.image', 'Image');

    const canvas = document.createElement('canvas');

    canvas.width = _width;
    canvas.height = _height;

    const ctx = canvas.getContext('2d');

    ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, _width, _height);

    const result = Sampler2D.uint8(4, _width, _height);

    canvasDataToSampler(result, ctx);

    return result;
}

/**
 *
 * @param {Texture} texture
 * @param {number} [width]
 * @param {number} [height]
 * @param {boolean} [flipY]
 * @return {Sampler2D}
 */
export function convertTexture2Sampler2D(
    texture,
    width,
    height,
    flipY = true
) {
    let _height = height;
    let _width = width;

    const channel_count = formatToChannelCount(texture.format);

    if (_width === undefined || _height === undefined) {

        //figure out texture size
        const image = texture.image;

        if (image !== undefined && image !== null) {
            if (_width === undefined) {
                if (typeof image.width === "number") {
                    _width = image.width;
                } else {
                    _width = DEFAULT_TEXTURE_WIDTH;
                }
            }
            if (_height === undefined) {
                if (typeof image.height === "number") {
                    _height = image.height;
                } else {
                    _height = DEFAULT_TEXTURE_HEIGHT;
                }
            }
        } else {
            if (_width === undefined) {
                _width = DEFAULT_TEXTURE_WIDTH;
            }

            if (_height === undefined) {
                _height = DEFAULT_TEXTURE_HEIGHT;
            }
        }

    }


    let data;

    if (texture.isDataTexture === true) {

        // special case
        const converted = data_texture_to_sampler(texture, channel_count, _width, _height);

        data = converted.data;

    } else if (texture.image instanceof Image) {
        const converted = html_image_texture_to_sampler(texture, channel_count, _width, _height);

        data = converted.data;
    } else {
        const built = WebGLRendererPool.global.use(renderer => {

            const ctx = renderer.getContext();

            //support for compressed textures
            ctx.getExtension("WEBGL_compressed_texture_s3tc");

            return ImageFilter(renderer, _width, _height, {
                vertexShader: CopyShader.vertexShader,
                fragmentShader: CopyShader.fragmentShader,
                uniforms: {
                    tDiffuse: {
                        value: texture,
                        type: 't'
                    },
                    opacity: { value: 1.0 }
                }
            });

        });

        data = built.array;
    }

    if (flipY) {
        sampler2d_flipY_in_place(data, _width, _height);
    }

    return new Sampler2D(data, 4, _width, _height);
}
