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

import com.mojang.blaze3d.platform.GlStateManager.DestFactor
import com.mojang.blaze3d.platform.GlStateManager.SourceFactor
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.block.model.ItemTransforms
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.core.particles.DustParticleOptions
import net.minecraft.world.item.ItemDisplayContext
import net.minecraft.world.level.levelgen.XoroshiroRandomSource
import org.joml.Vector3f
import org.lwjgl.opengl.GL14.glBlendColor
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.block.entity.matter.MatterReplicatorBlockEntity
import ru.dbotthepony.mc.otm.client.render.DynamicBufferSource
import ru.dbotthepony.mc.otm.client.render.lockBlendFunc
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.get
import ru.dbotthepony.mc.otm.core.math.normalizeAngleDeg
import ru.dbotthepony.mc.otm.core.math.rotateYDegrees
import ru.dbotthepony.mc.otm.isPaused

class MatterReplicatorRenderer(private val context: BlockEntityRendererProvider.Context) : BlockEntityRenderer<MatterReplicatorBlockEntity> {
	companion object {
		private val smoke = DustParticleOptions(Vector3f(1f, 1f, 1f), 1f)
		private val rand = XoroshiroRandomSource(System.nanoTime(), System.currentTimeMillis())
		private val source = DynamicBufferSource(maximalInitialBufferSize = 2 shl 10)
	}

	override fun render(
		tile: MatterReplicatorBlockEntity,
		partialTick: Float,
		pose: PoseStack,
		bufferSource: MultiBufferSource,
		packedLight: Int,
		packedOverlay: Int
	) {
		val item = tile.visualItemStack

		if (item.isEmpty) {
			return
		}

		pose.pushPose()

		pose.translate(0.5, 0.3, 0.5)
		pose.scale(0.3f, 0.3f, 0.3f)

		val diff = System.nanoTime() - tile.lastRender
		tile.lastRender = System.nanoTime()

		if (!isPaused)
			tile.particleRenderScore += diff

		if (tile.particleRenderScore > 30_000_000L) {
			tile.particleRenderScore = tile.particleRenderScore % 30_000_000L

			if (rand.nextDouble() > 0.75 && !isPaused && tile.blockState[WorkerState.WORKER_STATE] == WorkerState.WORKING) {
				val (x, y, z) = tile.blockPos
				tile.level?.addParticle(smoke, 0.3 + x + rand.nextDouble() * 0.4, 0.1 + y + rand.nextDouble() * 0.2, 0.3 + z + rand.nextDouble() * 0.4, 0.0, 0.0, 0.0)
			}
		}

		if (!isPaused)
			tile.renderRotation = normalizeAngleDeg(tile.renderRotation + diff / 10_000_000f)

		pose.rotateYDegrees(tile.renderRotation)

		val model = context.itemRenderer.getModel(
			item,
			tile.level,
			null,
			0
		)

		context.itemRenderer.render(
			item,
			ItemDisplayContext.NONE,
			false,
			pose,
			source,
			packedLight,
			packedOverlay,
			model
		)

		glBlendColor(1f, 1f, 1f, 1f - tile.visualProgress)

		RenderSystem.enableBlend()
		RenderSystem.blendFuncSeparate(
			SourceFactor.ONE_MINUS_CONSTANT_ALPHA,
			DestFactor.CONSTANT_ALPHA,
			SourceFactor.ZERO,
			DestFactor.ONE
		)

		lockBlendFunc = true

		try {
			source.endBatch()
		} finally {
			lockBlendFunc = false
		}

		RenderSystem.defaultBlendFunc()
		glBlendColor(0f, 0f, 0f, 0f)

		pose.popPose()
	}
}
