
@file:Suppress("unused")

package ru.dbotthepony.mc.otm.core.math

import org.joml.Matrix3f
import org.joml.Matrix4f
import org.joml.Vector3f
import org.joml.Vector4f
import ru.dbotthepony.mc.otm.core.math.IAngle
import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.math.asVector3f
import ru.dbotthepony.mc.otm.core.math.rotateAroundThis
import ru.dbotthepony.mc.otm.core.math.rotation
import ru.dbotthepony.mc.otm.core.math.rotationDegrees
import ru.dbotthepony.mc.otm.core.math.unaryMinus

fun Matrix4f.rotate(angle: IAngle): Matrix4f {
	mul(angle.rotationXYZW())
	return this
}

fun Matrix4f.translate(vector: Vector) {
	translate(-vector.asVector3f())
}

fun Matrix4f.rotateAroundPoint(point: Vector, axis: Vector, rotation: Float, isDegrees: Boolean = false) {
	val p = point.asVector3f()
	translate(-p)
	rotation(axis.rotateAroundThis(rotation, isDegrees)) // TODO: 1.19.3
	translate(p)
}

fun Matrix4f.rotateAroundPoint(point: Vector, axis: Vector3f, rotation: Float, isDegrees: Boolean = false) {
	val p = point.asVector3f()
	translate(-p)
	rotation(if (isDegrees) axis.rotationDegrees(rotation) else axis.rotation(rotation)) // TODO: 1.19.3
	translate(p)
}

fun Matrix4f.rotateAroundPoint(point: Vector, rotation: IAngle) {
	val p = point.asVector3f()
	translate(-p)
	mul(rotation.rotationXYZW())
	translate(p)
}

fun Matrix4f.rotateAroundPoint(point: Vector3f, axis: Vector, rotation: Float, isDegrees: Boolean = false) {
	translate(-point)
	rotation(axis.rotateAroundThis(rotation, isDegrees)) // TODO: 1.19.3
	translate(point)
}

fun Matrix4f.rotateAroundPoint(point: Vector3f, rotation: IAngle) {
	translate(-point)
	mul(rotation.rotationXYZW())
	translate(point)
}

fun Matrix4f.rotateAroundPoint(point: Vector3f, axis: Vector3f, rotation: Float, isDegrees: Boolean = false) {
	translate(-point)
	rotation(if (isDegrees) axis.rotationDegrees(rotation) else axis.rotation(rotation)) // TODO: 1.19.3
	translate(point)
}

fun Matrix3f.toMatrix4f(): Matrix4f {
	val result = Matrix4f()

	result.zero()

	result.m00(this.m00)
	result.m10(this.m10)
	result.m20(this.m20)
	result.m01(this.m01)
	result.m11(this.m11)
	result.m21(this.m21)
	result.m02(this.m02)
	result.m12(this.m12)
	result.m22(this.m22)

	return result
}

var Matrix4f.translation: Vector3f
	get() {
		return Vector3f(this[0, 3], this[1, 3], this[2, 3])
	}

	set(value) {
		this[0, 0] = 1f
		this[1, 1] = 1f
		this[2, 2] = 1f
		this[3, 3] = 1f

		this[0, 3] = value.x()
		this[1, 3] = value.y()
		this[2, 3] = value.z()
	}

var Matrix4f.translation4: Vector4f
	get() {
		return Vector4f(this[0, 3], this[1, 3], this[2, 3], this[3, 3])
	}

	set(value) {
		this[0, 0] = 1f
		this[1, 1] = 1f
		this[2, 2] = 1f
		this[3, 3] = 1f

		this[0, 3] = value.x()
		this[1, 3] = value.y()
		this[2, 3] = value.z()
		this[3, 3] = value.w()
	}
