package ru.dbotthepony.mc.otm.item.weapon

import net.minecraft.util.Mth
import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.math.times
import java.util.*
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin

private val random = Random()
private const val DEGS = PI / 180.0

class VelocityCalculation(
	xRot: Double,
	yRot: Double,
	zRot: Double = 0.0,
	force: Double,
	deviation: Double = 0.0,
	owner: Entity? = null,
) {
	constructor(
		xRot: Float,
		yRot: Float,
		zRot: Float = 0f,
		force: Double,
		deviation: Double = 0.0,
		owner: Entity? = null,
	) : this(xRot.toDouble(), yRot.toDouble(), zRot.toDouble(), force, deviation, owner)

	constructor(
		xRot: Float,
		yRot: Float,
		zRot: Float = 0f,
		force: Float,
		deviation: Double = 0.0,
		owner: Entity? = null,
	) : this(xRot.toDouble(), yRot.toDouble(), zRot.toDouble(), force.toDouble(), deviation, owner)

	constructor(
		xRot: Float,
		yRot: Float,
		zRot: Float = 0f,
		force: Float,
		deviation: Float,
		owner: Entity? = null,
	) : this(xRot.toDouble(), yRot.toDouble(), zRot.toDouble(), force.toDouble(), deviation.toDouble(), owner)

	constructor(
		owner: Entity,
		force: Float,
		deviation: Float,
	) : this(owner.xRot.toDouble() - 4.5 * (1 / force), owner.yRot.toDouble(), 0.0, force.toDouble(), deviation.toDouble(), owner)

	constructor(
		owner: Entity,
		force: Double,
		deviation: Float,
	) : this(owner.xRot.toDouble() - 4.5 * (1 / force), owner.yRot.toDouble(), 0.0, force, deviation.toDouble(), owner)

	constructor(
		owner: Entity,
		force: Double,
		deviation: Double,
	) : this(owner.xRot.toDouble() - 4.5 * (1 / force), owner.yRot.toDouble(), 0.0, force, deviation, owner)

	val xVelocity = -sin(yRot * DEGS) * cos(xRot * (PI / 180.0))
	val yVelocity = -sin((xRot + zRot) * DEGS)
	val zVelocity = cos(yRot * DEGS) * cos(xRot * DEGS)

	val velocity: Vec3

	init {
		var velocity = Vec3(
			xVelocity,
			yVelocity,
			zVelocity
		).normalize()

		velocity += Vec3(
			random.nextGaussian() * 0.0075 * deviation,
			random.nextGaussian() * 0.0075 * deviation,
			random.nextGaussian() * 0.0075 * deviation,
		)

		velocity *= force

		if (owner != null) {
			val ownerVel = owner.deltaMovement

			if (owner.onGround()) {
				velocity += ownerVel
			} else {
				velocity += Vec3(ownerVel.x, 0.0, ownerVel.z)
			}
		}

		this.velocity = velocity
	}

	val yRotation = Mth.atan2(velocity.x, velocity.z).toFloat() * (180f / Math.PI.toFloat())
	val xRotation = Mth.atan2(velocity.y, velocity.horizontalDistance()).toFloat() * (180f / Math.PI.toFloat())

	fun load(onto: Entity, withRotation: Boolean = true) {
		if (withRotation) {
			onto.xRot = xRotation
			onto.yRot = yRotation
		}

		onto.deltaMovement = velocity
	}
}
