import { DoubleSide, LinearFilter, Mesh, OrthographicCamera, Scene, ShaderMaterial, WebGLRenderTarget } from 'three';
import { FULL_SCREEN_QUAD_VERTEX_SHADER } from "../FULL_SCREEN_QUAD_VERTEX_SHADER.js";
import { FULL_SCREEN_TRIANGLE_GEOMETRY } from "../geometry/FULL_SCREEN_TRIANGLE_GEOMETRY.js";

/**
 *
 * @param {WebGLRenderer} renderer
 * @param {number} width
 * @param {number} height
 * @param {{vertexShader?:string,fragmentShader:string, uniforms?:Object, defines?:Object}} processShader
 * @param {Uint8Array|Uint8ClampedArray} [destination]
 * @return {{array: Uint8Array, renderer: WebGLRenderer}}
 */
function processTexture(
    renderer,
    width,
    height,
    processShader,
    destination
) {
    if (destination === undefined) {
        destination = new Uint8ClampedArray(width * height * 4);
    }

    //make a webgl renderer with orthographic camera
    renderer.setSize(width, height);
    //make camera
    const camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
    const scene = new Scene();
    scene.add(camera);

    //make a quad to render
    const material = new ShaderMaterial(Object.assign({ vertexShader: FULL_SCREEN_QUAD_VERTEX_SHADER }, processShader));

    material.lights = false;
    material.fog = false;
    material.uniformsNeedUpdate = true;
    material.needsUpdate = true;
    material.side = DoubleSide;

    const quad = new Mesh(FULL_SCREEN_TRIANGLE_GEOMETRY, material);

    scene.add(quad);

    //render
    const renderTargetOptions = {
        generateMipmaps: false,
        minFilter: LinearFilter,
        stencilBuffer: false,
        depthBuffer: false
    };

    const renderTarget = new WebGLRenderTarget(width, height, renderTargetOptions);

    const __rt = renderer.getRenderTarget(); // remember old renderer state

    renderer.setRenderTarget(renderTarget);

    renderer.render(scene, camera);

    const gl = renderer.getContext();

    //void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, ArrayBufferView? pixels)
    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, destination);

    // restore renderer state
    renderer.setRenderTarget(__rt);

    // cleanup resources
    renderTarget.dispose();
    material.dispose();

    return {
        array: destination,
        graphics: renderer
    };
}

export default processTexture;
