import { RenderPass }	from "../framework/RenderPass.js";

import Shader			from "../framework/WebGpu.js";

import Matrix4			from "../framework/Matrix4.js";


export class OceanSolidRenderPass extends RenderPass {

	async create( ) {

		this.shader					= new Shader( this.device );

		this.shader.topology		= "triangle-list";

		this.shader.setCanvas( this.pipeline.canvas );

		this._configureCanvasContext();

		await this.shader.setup( "shaders/ocean_render.wgsl" );

		this.shader.setAttribute( "position", this.pipeline.memory.positions );

		this.shader.setAttribute( "uv", this.pipeline.memory.uvs );

		this.shader.setIndices( this.pipeline.memory.indices );

		await this._loadBottomTexture();

	}


	async bindBuffers( ) {

		const memory				= this.pipeline.memory;

		const oceanBlock			= this.pipeline.getBlockByName( "ocean" );

		const colPass				= oceanBlock.getPass( "ColFFT" );

		const heightBuffer			= colPass.shader.getBuffer( "heightField" );

		const viewMatrixData		= this.pipeline.camera.getViewMatrix();

		const projectionMatrixData	= Matrix4.createProjectionMatrix( this.pipeline.camera, this.pipeline.canvas );

		const viewProjectionMatrix	= Matrix4.multiply( projectionMatrixData, viewMatrixData );

		const cameraWorldMatrix		= Matrix4.invert( viewMatrixData );

		const cameraPosition		= Matrix4.getColumn( cameraWorldMatrix, 3 );

		await this.shader.setBuffer( "heightField", heightBuffer );

		this.shader.setVariable( "renderParams", memory.renderParams );

		this.shader.setVariable( "viewProjection", viewProjectionMatrix );

		this.shader.setVariable( "cameraPosition", cameraPosition );

		this.shader.createBindGroups();

	}


	async execute( ) {

		await this.shader.renderToCanvas( this.shader.indexCount, 1 );

	}


	_configureCanvasContext( ) {

		if ( this.pipeline.canvasConfigured ) {
			return;
		}

		const context	= this.pipeline.canvas.getContext( "webgpu" );

		const format	= navigator.gpu.getPreferredCanvasFormat();

		context.configure( {
			device: this.device,
			format: format,
			alphaMode: "opaque"
		} );

		this.pipeline.canvasConfigured = true;

	}


	async _loadBottomTexture( ) {

		if ( this._bottomTextureLoaded ) {

			return;

		}

		if ( typeof document === "undefined" ) {

			return;

		}

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

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

		if ( !ctx ) {

			return;

		}

		const colorImage	= await this._loadImage( "resources/textures/ground/Ground093C_2K-PNG_Color.png" );

		const heightImage	= await this._loadImage( "resources/textures/heightmap/Terrain003_1K_Height512.png" );

		// COLOR
		canvas.width	= colorImage.width;
		canvas.height	= colorImage.height;

		ctx.clearRect( 0, 0, canvas.width, canvas.height );

		ctx.drawImage( colorImage, 0, 0 );

		let imageData	= ctx.getImageData( 0, 0, canvas.width, canvas.height );

		let pixels		= new Uint8Array( imageData.data );

		const colorTex	= this.shader.createTextureFromData( canvas.width, canvas.height, pixels );

		this.shader.setVariable( "bottomColorTex", colorTex );

		// HEIGHTMAP
		canvas.width	= heightImage.width;
		canvas.height	= heightImage.height;

		ctx.clearRect( 0, 0, canvas.width, canvas.height );

		ctx.drawImage( heightImage, 0, 0 );

		imageData		= ctx.getImageData( 0, 0, canvas.width, canvas.height );

		pixels			= new Uint8Array( imageData.data );

		const heightTex	= this.shader.createTextureFromData( canvas.width, canvas.height, pixels );

		this.shader.setVariable( "bottomHeightTex", heightTex );

		const sampler	= this.device.createSampler( {
			minFilter: "linear",
			magFilter: "linear",
			mipmapFilter: "linear",
			addressModeU: "repeat",
			addressModeV: "repeat"
		} );

		this.shader.setVariable( "bottomSampler", sampler );


		this._bottomTextureLoaded = true;

	}


	async _loadImage( url ) {

		return await new Promise( function( resolve, reject ) {

			const img = new Image( );

			img.onload	= function( ) { resolve( img ); };

			img.onerror	= function( event ) { reject( event ); };

			img.src		= url;

		} );

	}

}
