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

import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferUploader
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.VertexFormat
import net.minecraft.client.renderer.GameRenderer
import net.minecraftforge.client.event.RenderLevelStageEvent
import org.lwjgl.opengl.GL11.GL_LESS
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.config.ServerConfig
import ru.dbotthepony.mc.otm.core.math.Vector
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.linearInterpolation
import ru.dbotthepony.mc.otm.core.math.rotateX
import ru.dbotthepony.mc.otm.network.ShockwaveEffectPacket
import ru.dbotthepony.mc.otm.secondTimeD
import kotlin.math.PI

object ShockwaveRenderer {
	private val activeShockwaves = ArrayList<State>()

	private class State(val pos: Vector, val finalRadius: Float = 6f) {
		var radius = 0f
		var lastRender = secondTimeD

		init {
			synchronized(activeShockwaves) {
				activeShockwaves.add(this)
			}
		}

		fun render(event: RenderLevelStageEvent): Boolean {
			val diff = secondTimeD - lastRender

			radius += (diff * EXPANSION_PER_SECOND).toFloat()
			lastRender = secondTimeD

			if (radius <= finalRadius) {
				val builder = tesselator.builder

				RenderSystem.setShader(GameRenderer::getPositionShader)
				RenderSystem.setShaderColor(1f, 1f, 1f, linearInterpolation(radius / finalRadius, 0.5f, 0f))
				RenderSystem.defaultBlendFunc()
				RenderSystem.enableBlend()
				RenderSystem.enableDepthTest()
				RenderSystem.depthFunc(GL_LESS)

				builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION)

				event.poseStack.pushPose()
				val (x, y, z) = event.camera.position
				event.poseStack.translate(pos.x - x, pos.y - y + 0.1f, pos.z - z) // render slightly above landed position
				event.poseStack.rotateX(PI.toFloat() / 2f)
				uploadArc(event.poseStack.last.pose, builder, x = 0f, y = 0f, innerRadius = (radius - 1f).coerceAtLeast(0f), outerRadius = radius, triangleFan = false)
				event.poseStack.popPose()

				BufferUploader.drawWithShader(builder.end())
			}

			return radius <= finalRadius
		}
	}

	private const val EXPANSION_PER_SECOND = 18f

	fun onRender(event: RenderLevelStageEvent) {
		if (event.stage !== RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) {
			return
		}

		synchronized(activeShockwaves) {
			val iterator = activeShockwaves.listIterator()

			for (value in iterator) {
				if (!value.render(event)) {
					iterator.remove()
				}
			}
		}
	}

	fun handle(packet: ShockwaveEffectPacket) {
		State(packet.pos, AndroidConfig.Shockwave.RADIUS_HORIZONTAL.toFloat())
	}
}
