package ru.dbotthepony.mc.otm.android.feature

import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.ChatFormatting
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.util.RandomSource
import net.minecraft.world.level.Level
import net.minecraft.world.phys.Vec3
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor
import net.minecraftforge.network.PacketDistributor.TargetPoint
import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.ShiftPressedCond
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.core.math.RGBAColor
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.util.formatPower
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
import ru.dbotthepony.mc.otm.network.enqueueWork
import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.network.sender
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.registry.MSoundEvents
import java.util.function.Supplier

private fun makeSmoke(x: Double, y: Double, z: Double, random: RandomSource, level: Level) {
	for (i in 0 .. random.nextInt(4, 8))
		level.addParticle(ParticleTypes.POOF, x + random.nextDouble() * 0.5 - 0.25, y + random.nextDouble() * 0.5 - 0.25, z + random.nextDouble() * 0.5 - 0.25, random.nextGaussian() * 0.02, random.nextGaussian() * 0.02, random.nextGaussian() * 0.02)
}

object TriggerJumpBoostPacket : MatteryPacket {
	override fun write(buff: FriendlyByteBuf) {
		// no op
	}

	override fun play(context: Supplier<NetworkEvent.Context>) {
		context.packetHandled = true

		context.enqueueWork {
			val mattery = context.sender?.matteryPlayer ?: return@enqueueWork

			if (!mattery.isAndroid)
				return@enqueueWork

			val feature = mattery.getFeature(AndroidFeatures.JUMP_BOOST) ?: return@enqueueWork

			if (feature.isActive && feature.cooldown <= 4 && mattery.androidEnergy.extractEnergyExact(AndroidConfig.JumpBoost.ENERGY_COST, false)) {
				feature.putOnCooldown()

				context.sender?.let {
					it.level().playSound(
						it, it,
						MSoundEvents.ANDROID_JUMP_BOOST, SoundSource.PLAYERS,
						1f, 1f
					)

					MatteryPlayerNetworkChannel.send(PacketDistributor.NEAR.with { TargetPoint(it, it.x, it.y, it.z, 64.0, it.level().dimension()) }, JumpBoostParticlesPacket(it.x, it.y, it.z))
				}
			}
		}
	}
}

class JumpBoostParticlesPacket(val x: Double, val y: Double, val z: Double) : MatteryPacket {
	override fun write(buff: FriendlyByteBuf) {
		buff.writeDouble(x)
		buff.writeDouble(y)
		buff.writeDouble(z)
	}

	override fun play(context: Supplier<NetworkEvent.Context>) {
		context.packetHandled = true
		context.enqueueWork {
			minecraft.player?.level()?.let {
				makeSmoke(x, y, z, it.random, it)
			}
		}
	}

	companion object {
		fun read(buff: FriendlyByteBuf): JumpBoostParticlesPacket {
			return JumpBoostParticlesPacket(buff.readDouble(), buff.readDouble(), buff.readDouble())
		}
	}
}

class JumpBoostFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.JUMP_BOOST, capability) {
	private var tickCooldownClient = false

	override val maxCooldown: Int
		get() = (AndroidConfig.JumpBoost.BASE_COOLDOWN - AndroidConfig.JumpBoost.COOLDOWN_REDUCTION * level).coerceAtLeast(0)

	override var cooldown by synchronizer.int(setter = setter@{ value, access, setByRemote ->
		access.write(value)

		if (setByRemote) {
			tickCooldownClient = false
		}
	}).property

	private var lastGround = false

	fun movementTick(isJumping: Boolean, isShifting: Boolean) {
		check(ply !is ServerPlayer) { "Invalid side" }

		if (ply.isSpectator) {
			return
		}

		val old = lastGround
		lastGround = ply.onGround()

		if (isActive && cooldown <= 0 && old != lastGround && !lastGround && isJumping && isShifting && ply.xRot <= ClientConfig.JUMP_BOOST_LOOK_ANGLE && android.androidEnergy.extractEnergyExact(AndroidConfig.JumpBoost.ENERGY_COST, true)) {
			ply.deltaMovement += Vector(0.0, AndroidConfig.JumpBoost.POWER * (level + 1) / 20.0, 0.0)
			putOnCooldown()
			MatteryPlayerNetworkChannel.sendToServer(TriggerJumpBoostPacket)

			ply.level().playSound(
				ply, ply,
				MSoundEvents.ANDROID_JUMP_BOOST, SoundSource.PLAYERS,
				1f, 1f
			)

			makeSmoke(ply.x, ply.y, ply.z, ply.random, ply.level())
		}
	}

	override fun tickClient() {
		if (tickCooldownClient && cooldown > 0) {
			cooldown--
		}
	}

	override fun renderIcon(graphics: GuiGraphics, x: Float, y: Float, width: Float, height: Float, color: RGBAColor) {
		ResearchIcons.ICON_JUMP_BOOST.render(graphics, x, y, width, height, color = if (cooldown > 0) color * RGBAColor.REDDISH else color)
	}
}
