package ru.dbotthepony.mc.otm.client

import com.mojang.blaze3d.platform.InputConstants
import com.mojang.blaze3d.platform.Window
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Font
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.sounds.SoundEvents
import org.lwjgl.glfw.GLFW
import org.lwjgl.glfw.GLFW.GLFW_CURSOR
import ru.dbotthepony.mc.otm.isClient
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.DoubleBuffer
import java.util.function.BooleanSupplier

inline val minecraft: Minecraft get() = Minecraft.getInstance()
inline val font: Font get() = minecraft.font

fun Window.isKeyDown(key: Int) = InputConstants.isKeyDown(window, key)

val Window.isShiftDown get() = isKeyDown(InputConstants.KEY_LSHIFT) || isKeyDown(InputConstants.KEY_RSHIFT)
val Window.isCtrlDown get() = isKeyDown(InputConstants.KEY_RCONTROL) || isKeyDown(InputConstants.KEY_LCONTROL)
val Window.isAltDown get() = isKeyDown(InputConstants.KEY_RALT) || isKeyDown(InputConstants.KEY_LALT)

object ShiftPressedCond : BooleanSupplier {
	override fun getAsBoolean(): Boolean {
		if (isClient) {
			return impl()
		}

		return false
	}

	private fun impl(): Boolean {
		return minecraft.window.isShiftDown
	}
}

object ShiftDepressedCond : BooleanSupplier {
	override fun getAsBoolean(): Boolean {
		return !ShiftPressedCond.asBoolean
	}
}

fun playGuiClickSound() {
	minecraft.soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0f))
}

fun setMousePos(x: Double, y: Double) {
	GLFW.glfwSetCursorPos(minecraft.window.window, x, y)
}

fun setMousePosScaled(x: Double, y: Double) {
	GLFW.glfwSetCursorPos(minecraft.window.window, x * minecraft.window.guiScale, y * minecraft.window.guiScale)
}

fun setMousePos(x: Float, y: Float) {
	GLFW.glfwSetCursorPos(minecraft.window.window, x.toDouble(), y.toDouble())
}

fun setMousePosScaled(x: Float, y: Float) {
	GLFW.glfwSetCursorPos(minecraft.window.window, x * minecraft.window.guiScale, y * minecraft.window.guiScale)
}

private val cursorXPosBuf = ByteBuffer.allocateDirect(8).also { it.order(ByteOrder.LITTLE_ENDIAN) }.asDoubleBuffer()
private val cursorYPosBuf = ByteBuffer.allocateDirect(8).also { it.order(ByteOrder.LITTLE_ENDIAN) }.asDoubleBuffer()

data class ScaledMousePos(val x: Double, val y: Double) {
	fun set() {
		setMousePos(x * minecraft.window.guiScale, y * minecraft.window.guiScale)
	}

	fun move(x: Double = 0.0, y: Double = 0.0) {
		GLFW.glfwSetCursorPos(minecraft.window.window, this.x * minecraft.window.guiScale + x, this.y * minecraft.window.guiScale + y)
	}

	fun move(x: Float = 0.0f, y: Float = 0.0f) {
		GLFW.glfwSetCursorPos(minecraft.window.window, this.x * minecraft.window.guiScale + x, this.y * minecraft.window.guiScale + y)
	}

	fun moveScaled(x: Double = 0.0, y: Double = 0.0) {
		GLFW.glfwSetCursorPos(minecraft.window.window, this.x * minecraft.window.guiScale + x * minecraft.window.guiScale, this.y * minecraft.window.guiScale + y * minecraft.window.guiScale)
	}

	fun moveScaled(x: Float = 0.0f, y: Float = 0.0f) {
		GLFW.glfwSetCursorPos(minecraft.window.window, this.x * minecraft.window.guiScale + x * minecraft.window.guiScale, this.y * minecraft.window.guiScale + y * minecraft.window.guiScale)
	}
}

data class MousePos(val x: Double, val y: Double) {
	fun set() {
		setMousePos(x, y)
	}

	fun move(x: Double = 0.0, y: Double = 0.0) {
		GLFW.glfwSetCursorPos(minecraft.window.window, this.x + x, this.y + y)
	}

	fun move(x: Float = 0.0f, y: Float = 0.0f) {
		GLFW.glfwSetCursorPos(minecraft.window.window, this.x + x, this.y + y)
	}

	fun moveScaled(x: Double = 0.0, y: Double = 0.0) {
		GLFW.glfwSetCursorPos(minecraft.window.window, this.x + x * minecraft.window.guiScale, this.y + y * minecraft.window.guiScale)
	}

	fun moveScaled(x: Float = 0.0f, y: Float = 0.0f) {
		GLFW.glfwSetCursorPos(minecraft.window.window, this.x + x * minecraft.window.guiScale, this.y + y * minecraft.window.guiScale)
	}
}

val mousePos: MousePos get() {
	cursorXPosBuf.position(0)
	cursorYPosBuf.position(0)

	GLFW.glfwGetCursorPos(minecraft.window.window, cursorXPosBuf, cursorYPosBuf)

	cursorXPosBuf.position(0)
	cursorYPosBuf.position(0)

	return MousePos(cursorXPosBuf.get(), cursorYPosBuf.get())
}

val scaledMousePos: ScaledMousePos get() {
	cursorXPosBuf.position(0)
	cursorYPosBuf.position(0)

	GLFW.glfwGetCursorPos(minecraft.window.window, cursorXPosBuf, cursorYPosBuf)

	cursorXPosBuf.position(0)
	cursorYPosBuf.position(0)

	return ScaledMousePos(cursorXPosBuf.get() / minecraft.window.guiScale, cursorYPosBuf.get() / minecraft.window.guiScale)
}

fun moveMousePos(x: Double = 0.0, y: Double = 0.0) {
	val (currentX, currentY) = mousePos
	GLFW.glfwSetCursorPos(minecraft.window.window, currentX + x, currentY + y)
}

fun moveMousePos(x: Float = 0.0f, y: Float = 0.0f) {
	val (currentX, currentY) = mousePos
	GLFW.glfwSetCursorPos(minecraft.window.window, currentX + x, currentY + y)
}

fun moveMousePosScaled(x: Double = 0.0, y: Double = 0.0) {
	val (currentX, currentY) = mousePos
	GLFW.glfwSetCursorPos(minecraft.window.window, currentX + x * minecraft.window.guiScale, currentY + y * minecraft.window.guiScale)
}

fun moveMousePosScaled(x: Float = 0.0f, y: Float = 0.0f) {
	val (currentX, currentY) = mousePos
	GLFW.glfwSetCursorPos(minecraft.window.window, currentX + x * minecraft.window.guiScale, currentY + y * minecraft.window.guiScale)
}

var mouseInputMode: Int
	get() = GLFW.glfwGetInputMode(minecraft.window.window, GLFW_CURSOR)
	set(value) { GLFW.glfwSetInputMode(minecraft.window.window, GLFW_CURSOR, value) }
