package speiger.src.coreengine.platform.graphics.api.mesh;

import java.util.Objects;
import java.util.OptionalInt;

import org.jspecify.annotations.Nullable;

import speiger.src.collections.ints.collections.IntIterable;
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.coreengine.platform.graphics.api.buffer.VertexBuffer;
import speiger.src.coreengine.platform.graphics.api.buffer.states.BufferState;
import speiger.src.coreengine.platform.graphics.api.buffer.states.IndeciesType;
import speiger.src.coreengine.platform.graphics.api.utils.GraphicsResource;

public abstract class DynamicMesh implements GraphicsResource {
	protected Int2ObjectMap<VertexBuffer> buffers;
	@Nullable
	protected VertexBuffer indeciesBuffer;
	@Nullable
	protected IndeciesType indeciesType;
	
	public DynamicMesh(Int2ObjectMap<VertexBuffer> buffers, @Nullable VertexBuffer indeciesBuffer, @Nullable IndeciesType type) {
		this.buffers = buffers;
		this.indeciesBuffer = indeciesBuffer;
	}
	
	public abstract void closeWithBuffers();
	
	@Nullable
	public VertexBuffer indeciesBuffer() {
		return indeciesBuffer;
	}
	
	@Nullable
	public IndeciesType indeciesType() {
		return indeciesType;
	}
	
	public VertexBuffer buffer(int binding) {
		return buffers.get(binding);
	}
	
	public DynamicMesh indexBuffer(@Nullable VertexBuffer indexBuffer, @Nullable IndeciesType indeciesType) {
		this.indeciesBuffer = indexBuffer;
		this.indeciesType = indeciesType;
		return this;
	}
	
	public DynamicMesh buffer(int binding, @Nullable VertexBuffer buffer) {
		buffers.put(binding, buffer);
		return this;
	}
	
	public IntIterable bindings() {
		return buffers.keySet().unmodifiable();
	}
	
	public static Builder builder() {
		return new Builder();
	}
	
	public static class Builder {
		Int2ObjectMap<BufferState> allocateState = new Int2ObjectOpenHashMap<>();
		IndeciesType type = IndeciesType.INT;
		OptionalInt preallocated = OptionalInt.empty();
		boolean autoGenerate;
		
		private Builder() {}
		
		public Builder autogenerate() {
			autoGenerate = true;
			return this;
		}
		
		public Builder preallocate(int bytes) {
			preallocated = OptionalInt.of(bytes);
			return this;
		}
		
		public Builder indecies(IndeciesType type) {
			type = Objects.requireNonNull(type);
			return this;
		}
		
		public Builder bufferState(int index, BufferState state) {
			allocateState.put(index, state);
			return this;
		}
				
		public boolean isAutogenerated() {
			return autoGenerate;
		}
		
		public IndeciesType indecies() {
			return type;
		}
		
		public OptionalInt preAllocated() {
			return preallocated;
		}
		
		public Int2ObjectMap<BufferState> buffers() {
			return allocateState.unmodifiable();
		}

		public BufferState getIndeciesBuffer() {
			return allocateState.getOrDefault(-1, BufferState.STATIC_DRAW);
		}
	}
}
