package ru.dbotthepony.mc.otm.client.render

import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexFormat
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderStateShard
import net.minecraft.client.renderer.RenderType
import net.minecraft.core.BlockPos
import org.lwjgl.opengl.GL11.GL_LESS
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.core.math.component1
import ru.dbotthepony.mc.otm.core.math.component2
import ru.dbotthepony.mc.otm.core.math.component3
import ru.dbotthepony.mc.otm.core.math.minus
import ru.dbotthepony.mc.otm.core.multiblock.IMultiblockAccess
import ru.dbotthepony.mc.otm.core.multiblock.NodeStatus

private val UNKNOWN = RGBAColor.YELLOW.copy(alpha = 0.5f)
private val VALID = RGBAColor.DARK_GREEN.copy(alpha = 0.5f)
private val INVALID = RGBAColor.DARK_RED.copy(alpha = 0.5f)

val MULTIBLOCK_STATUS_RENDER_TYPE = run {
	val builder = RenderType.CompositeState.builder()

	builder.setShaderState(RenderStateShard.ShaderStateShard(GameRenderer::getPositionColorShader))
	builder.setDepthTestState(RenderStateShard.DepthTestStateShard("less", GL_LESS))

	builder.setTransparencyState(RenderStateShard.TransparencyStateShard("normal_blend", {
		RenderSystem.enableBlend()
		RenderSystem.defaultBlendFunc()
	}, { RenderSystem.disableBlend() }))

	@Suppress("INACCESSIBLE_TYPE")
	RenderType.create(
		"otm_multiblock_status",
		DefaultVertexFormat.POSITION_COLOR,
		VertexFormat.Mode.QUADS,
		256_000,
		false,
		false,
		builder.createCompositeState(false)
	) as RenderType
}

fun IMultiblockAccess.render(
	poseStack: PoseStack,
	buffers: MultiBufferSource,
	relativePos: BlockPos,
) {
	val buffer = buffers.getBuffer(MULTIBLOCK_STATUS_RENDER_TYPE)
	val nodes = currentNodes

	for (node in nodes.values) {
		if (node.displayBlocks.isNotEmpty() && node.status == NodeStatus.VALID) {
			continue
		}

		// TODO: rendering
		// TODO: rendering
		// TODO: rendering
		// TODO: Rendering
		// TODO: Rendering...
		// TODO: Rendering!..
		// TODO: Rendering!..
		// TODO: Rendering!
		// TODO: Rendering!!
		// TODO: RENDERING!!
		// TODO: RENDERING!!!

		val color = when (node.status) {
			NodeStatus.UNKNOWN -> UNKNOWN
			NodeStatus.VALID -> VALID
			NodeStatus.INVALID -> INVALID
		}

		val (x, y, z) = node.pos - relativePos

		if (nodes[node.pos.south()]?.status != node.status) {
			// south
			buffer.vertex(poseStack, x.toFloat(), y.toFloat(), z.toFloat() + 1f).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat(), z.toFloat() + 1f).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat() + 1f, z.toFloat() + 1f).color(color)
			buffer.vertex(poseStack, x.toFloat(), y.toFloat() + 1f, z.toFloat() + 1f).color(color)
		}

		if (nodes[node.pos.north()]?.status != node.status) {
			// north
			buffer.vertex(poseStack, x.toFloat(), y.toFloat(), z.toFloat()).color(color)
			buffer.vertex(poseStack, x.toFloat(), y.toFloat() + 1f, z.toFloat()).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat() + 1f, z.toFloat()).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat(), z.toFloat()).color(color)
		}

		if (nodes[node.pos.above()]?.status != node.status) {
			// up
			buffer.vertex(poseStack, x.toFloat(), y.toFloat() + 1f, z.toFloat()).color(color)
			buffer.vertex(poseStack, x.toFloat(), y.toFloat() + 1f, z.toFloat() + 1f).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat() + 1f, z.toFloat() + 1f).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat() + 1f, z.toFloat()).color(color)
		}

		if (nodes[node.pos.below()]?.status != node.status) {
			// down
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat(), z.toFloat() + 1f).color(color)
			buffer.vertex(poseStack, x.toFloat(), y.toFloat(), z.toFloat() + 1f).color(color)
			buffer.vertex(poseStack, x.toFloat(), y.toFloat(), z.toFloat()).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat(), z.toFloat()).color(color)
		}

		if (nodes[node.pos.east()]?.status != node.status) {
			// east
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat(), z.toFloat()).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat() + 1f, z.toFloat()).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat() + 1f, z.toFloat() + 1f).color(color)
			buffer.vertex(poseStack, x.toFloat() + 1f, y.toFloat(), z.toFloat() + 1f).color(color)
		}

		if (nodes[node.pos.west()]?.status != node.status) {
			// west
			buffer.vertex(poseStack, x.toFloat(), y.toFloat() + 1f, z.toFloat() + 1f).color(color)
			buffer.vertex(poseStack, x.toFloat(), y.toFloat() + 1f, z.toFloat()).color(color)
			buffer.vertex(poseStack, x.toFloat(), y.toFloat(), z.toFloat()).color(color)
			buffer.vertex(poseStack, x.toFloat(), y.toFloat(), z.toFloat() + 1f).color(color)
		}
	}
}
