package speiger.src.coreengine.platform.graphics.api.vertex.builder;

import speiger.src.coreengine.math.vector.matrix.Matrix4f;
import speiger.src.coreengine.platform.graphics.api.shader.states.DrawMode;
import speiger.src.coreengine.platform.graphics.api.shader.states.GraphicsDataType;
import speiger.src.coreengine.platform.graphics.api.vertex.VertexLayout.Element;
import speiger.src.coreengine.platform.graphics.api.vertex.VertexLayout.Usage;

public interface IVertexBuffer extends IVertexBuilder {
	Element current();
	IVertexBuffer next();
	BufferResult finish();
	default IVertexBuffer validate(Usage usage, GraphicsDataType type, int size) { return validate(this, usage, type, size); }
	
	
	IVertexBuffer put(int byteOffset, byte value);
	IVertexBuffer putShort(int byteOffset, short value);
	IVertexBuffer putInt(int byteOffset, int value);
	IVertexBuffer putFloat(int byteOffset, float value);
	
	int vertecies();
	
	@Override
	default IVertexBuffer pos(float x, float y) { return validate(Usage.POS, GraphicsDataType.FLOAT, 2).putFloat(0, x).putFloat(4, y).next(); }
	@Override
	default IVertexBuffer pos(float x, float y, float z) { return validate(Usage.POS, GraphicsDataType.FLOAT, 3).putFloat(0, x).putFloat(4, y).putFloat(8, z).next(); }
	@Override
	default IVertexBuffer rgb(int r, int g, int b) { return validate(Usage.COLOR, GraphicsDataType.UNSIGNED_BYTE, 3).put(0, (byte)r).put(1, (byte)g).put(2, (byte)b).next(); }
	@Override
	default IVertexBuffer rgba(int r, int g, int b, int a) { return validate(Usage.COLOR, GraphicsDataType.UNSIGNED_BYTE, 4).put(0, (byte)r).put(1, (byte)g).put(2, (byte)b).put(3, (byte)a).next(); }
	@Override
	default IVertexBuffer tex(float u, float v) { return validate(Usage.UV, GraphicsDataType.FLOAT, 2).putFloat(0, u).putFloat(4, v).next(); }
	@Override
	default IVertexBuffer normal(float x, float y, float z) { return validate(Usage.NORMAL, GraphicsDataType.FLOAT, 3).putFloat(0, x).putFloat(4, y).putFloat(8, z).next(); }
	default IVertexBuffer matrix(Matrix4f mat) {
		validate(Usage.MATRIX, GraphicsDataType.FLOAT, 16);
		for(int i = 0;i<16;i++) {
			putFloat(i*4, mat.get(i));
		}
		return next();
	}
	
	static IVertexBuffer validate(IVertexBuffer builder, Usage usage, GraphicsDataType type, int size) {
		Element current = builder.current();
		if(current.size() == size && current.usage() == usage && current.type() == type) return builder;
		throw new IllegalStateException("Expected State [Usage="+current.usage()+", Size="+current.size()+", Type="+current.type()+"], wasn't present. Actual State [Usage="+usage+", Size="+size+", Type="+type+"]");
	}
	
	public record BufferResult(DrawMode mode, int startVertex, int endVertex) {
		public int vertexCount() { return endVertex - startVertex; }
	}
}
