import 	sdl 			from '@kmamal/sdl'

import 	gpu 			from '@kmamal/gpu'

import Shader 			from "../../framework/WebGpu_node.js"

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

import Vector3 			from "../../framework/Vector3.js"

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

import EventManager 	from "../../framework/eventManager_node.js";

import { readFileSync } from "node:fs";


const window 		= sdl.video.createWindow({ webgpu: true })

var canvas			= window;

const instance 		= gpu.create([ 'verbose=1' ])

console.log("devices", gpu)

const adapter 		= await instance.requestAdapter()

const device 		= await adapter.requestDevice()


const renderer = gpu.renderGPUDeviceToWindow({ device, window })


canvas.getContext = function() {

	return renderer;

}



var renderShader 		= new Shader( device );


renderShader.setCanvas( canvas );

renderShader.topology = "triangle-list";

await renderShader.setup( "../../shaders/triangle-list.wgsl");

async function loadJSON( pathName ) {

	const json = await readFileSync( pathName, 'utf8' )

	return JSON.parse( json );
}

	var camera 			= new Camera( [0, 0, 1115], [0, -.3, 0], [0, 1, 0] );

	

	var eventManager		= new EventManager( canvas );

	eventManager.setup( canvas, camera );

	eventManager.registerEventListenersNode();

	var frameCount 			= 0;



var model				= await loadJSON("../../models/demo.json");

var mesh				= model.meshes[0];


const instanceCount = 100;
const instancePositions = new Float32Array(instanceCount * 4); // vec4 per instance

for (let i = 0; i < instanceCount; i++) {

	const x = (i % 10) * 300.0;
	const y = Math.floor(i / 10) * 350.0;

	instancePositions[i * 4 + 0] = x - 500;
	instancePositions[i * 4 + 1] = 0;
	instancePositions[i * 4 + 2] = y - 500;
	instancePositions[i * 4 + 3] = 0; 
}


		renderShader.setAttribute( "position", mesh.vertices );

		renderShader.setAttribute( "normal", mesh.normals );

		renderShader.setVariable( "instancePositions", instancePositions );


		var faces	= mesh.faces;

		const indexArray = new Uint32Array(faces.length * 3);

		for (let i = 0; i < faces.length; i++) {

		    indexArray[i * 3 + 0] 	= faces[i][0];

		    indexArray[i * 3 + 1] 	= faces[i][1];

		    indexArray[i * 3 + 2] 	= faces[i][2];

		}

		renderShader.setIndices( indexArray );

		var lastFrameTime = 0;

	

	function updateTimeDelta() {

		const now				= performance.now();

		deltaTimeValue		= ( now - lastFrameTime ) / 1000;

		lastFrameTime		= now;

	}

	var frameCount = 0;

	var deltaTimeValue = 0;

	var vertexCount = 1;

const render = () => {

		if (window.destroyed) { return }

		updateTimeDelta();

		const viewMatrixData 			= camera.getViewMatrix();

		const projectionMatrixData 		= Matrix4.createProjectionMatrix( camera, canvas )

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

		const cameraWorldMatrix 		= Matrix4.invert( viewMatrixData );  

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

		renderShader.setVariable( "viewProjectionMatrix", viewProjectionMatrix );

		renderShader.setVariable( "cameraPosition", cameraPosition );

		frameCount++;

	
		renderShader.renderToCanvas( vertexCount, 60, 0, frameCount )


		renderer.swap()


		frameCount++;

		setTimeout(render, 0)
	}

render();


window.on('close', () => {
	device.destroy()
	gpu.destroy(instance)
})






//console.log(model);

/*
const renderer = gpu.renderGPUDeviceToWindow({ device, window })

const positions = new Float32Array([
	...[ 1.0, -1.0, 0.0 ],
	...[ -1.0, -1.0, 0.0 ],
	...[ 0.0, 1.0, 0.0 ],
])

const colors = new Float32Array([
	...[ 1.0, 0.0, 0.0 ],
	...[ 0.0, 1.0, 0.0 ],
	...[ 0.0, 0.0, 1.0 ],
])

const indices = new Uint16Array([ 0, 1, 2 ])

const createBuffer = (arr, usage) => {
	const buffer = device.createBuffer({
		size: (arr.byteLength + 3) & ~3,
		usage,
		mappedAtCreation: true,
	})

	const writeArray = arr instanceof Uint16Array
		? new Uint16Array(buffer.getMappedRange())
		: new Float32Array(buffer.getMappedRange())
	writeArray.set(arr)
	buffer.unmap()
	return buffer
}

const positionBuffer = createBuffer(positions, gpu.GPUBufferUsage.VERTEX)
const colorBuffer = createBuffer(colors, gpu.GPUBufferUsage.VERTEX)
const indexBuffer = createBuffer(indices, gpu.GPUBufferUsage.INDEX)

const vertexShaderFile = path.join(__dirname, 'vertex.wgsl')
const vertexShaderCode = await fs.promises.readFile(vertexShaderFile, 'utf8')

const fragmentShaderFile = path.join(__dirname, 'fragment.wgsl')
const fragmentShaderCode = await fs.promises.readFile(fragmentShaderFile, 'utf8')

const pipeline = device.createRenderPipeline({
	layout: 'auto',
	vertex: {
		module: device.createShaderModule({ code: vertexShaderCode }),
		entryPoint: 'main',
		buffers: [
			{
				attributes: [
					{
						shaderLocation: 0,
						offset: 0,
						format: 'float32x3',
					},
				],
				arrayStride: 3 * Float32Array.BYTES_PER_ELEMENT,
				stepMode: 'vertex',
			},
			{
				attributes: [
					{
						shaderLocation: 1,
						offset: 0,
						format: 'float32x3',
					},
				],
				arrayStride: 3 * Float32Array.BYTES_PER_ELEMENT,
				stepMode: 'vertex',
			},
		],
	},
	fragment: {
		module: device.createShaderModule({ code: fragmentShaderCode }),
		entryPoint: 'main',
		targets: [ { format: renderer.getPreferredFormat() } ],
	},
	primitive: {
		topology: 'triangle-list',
	},
})

const render = () => {
	if (window.destroyed) { return }

	const commandEncoder = device.createCommandEncoder()

	const renderPass = commandEncoder.beginRenderPass({
		colorAttachments: [
			{
				view: renderer.getCurrentTextureView(),
				clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
				loadOp: 'clear',
				storeOp: 'store',
			},
		],
	})
	renderPass.setPipeline(pipeline)
	renderPass.setViewport(0, 0, width, height, 0, 1)
	renderPass.setScissorRect(0, 0, width, height)
	renderPass.setVertexBuffer(0, positionBuffer)
	renderPass.setVertexBuffer(1, colorBuffer)
	renderPass.setIndexBuffer(indexBuffer, 'uint16')
	renderPass.drawIndexed(3)
	renderPass.end()

	device.queue.submit([ commandEncoder.finish() ])

	renderer.swap()

	setTimeout(render, 0)
}

render()

window.on('close', () => {
	device.destroy()
	gpu.destroy(instance)
})

*/