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

import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.properties.EnumProperty
import ru.dbotthepony.mc.otm.core.get
import java.util.EnumMap

internal inline val BlockState.rotationOne: BlockRotation get() = this[BlockRotationFreedom.ONE.property]
internal inline val BlockState.rotationTwo: BlockRotation get() = this[BlockRotationFreedom.TWO.property]
internal inline val BlockState.rotationThree: BlockRotation get() = this[BlockRotationFreedom.THREE.property]

internal inline val BlockState.facingOne: Direction get() = this[BlockRotationFreedom.ONE.property].front
internal inline val BlockState.facingTwo: Direction get() = this[BlockRotationFreedom.TWO.property].front
internal inline val BlockState.facingThree: Direction get() = this[BlockRotationFreedom.THREE.property].front

/**
 * Controls the rotational freedom of block in space, employing [property] and [of] to get valid value from set of possible values
 */
enum class BlockRotationFreedom(vararg values: BlockRotation) {
	ONE(
		BlockRotation.NORTH,
		BlockRotation.SOUTH,
		BlockRotation.WEST,
		BlockRotation.EAST,
	),
	TWO(
		BlockRotation.DOWN,
		BlockRotation.UP,
		BlockRotation.NORTH,
		BlockRotation.SOUTH,
		BlockRotation.WEST,
		BlockRotation.EAST,
	),
	THREE(
		BlockRotation.DOWN,
		BlockRotation.UP,
		BlockRotation.NORTH,
		BlockRotation.SOUTH,
		BlockRotation.WEST,
		BlockRotation.EAST,
		BlockRotation.DOWN_SOUTH,
		BlockRotation.DOWN_WEST,
		BlockRotation.DOWN_EAST,
		BlockRotation.UP_SOUTH,
		BlockRotation.UP_WEST,
		BlockRotation.UP_EAST,
	),

	/**
	 * These rotations are impossible to achieve using blockstates because blockstate def can't rotate models in XY plane (z axis)
	 */
	FOUR(
		BlockRotation.DOWN,
		BlockRotation.UP,
		BlockRotation.NORTH,
		BlockRotation.SOUTH,
		BlockRotation.WEST,
		BlockRotation.EAST,
		BlockRotation.DOWN_SOUTH,
		BlockRotation.DOWN_WEST,
		BlockRotation.DOWN_EAST,
		BlockRotation.UP_SOUTH,
		BlockRotation.UP_WEST,
		BlockRotation.UP_EAST,
		BlockRotation.NORTH_DOWN,
		BlockRotation.SOUTH_DOWN,
		BlockRotation.WEST_DOWN,
		BlockRotation.EAST_DOWN,
	);

	val possibleValues: Collection<BlockRotation> get() = property.possibleValues
	val property: EnumProperty<BlockRotation> = EnumProperty.create("facing", BlockRotation::class.java, *values)

	private val oneDirection = EnumMap<Direction, BlockRotation>(Direction::class.java)
	private val twoDirection = EnumMap<Direction, EnumMap<Direction, BlockRotation>>(Direction::class.java)

	init {
		for (direction in Direction.values()) {
			oneDirection[direction] = possibleValues.firstOrNull { it.front == direction }
				?: possibleValues.first()

			val second = EnumMap<Direction, BlockRotation>(Direction::class.java)
			twoDirection[direction] = second

			for (direction2 in Direction.values()) {
				second[direction2] = possibleValues.firstOrNull { it.front == direction && it.top == direction2 }
					?: possibleValues.firstOrNull { it.front == direction }
					?: possibleValues.first()
			}
		}
	}

	fun of(front: Direction): BlockRotation {
		return oneDirection[front]!!
	}

	fun of(front: Direction, top: Direction = Direction.UP): BlockRotation {
		return twoDirection[front]!![top]!!
	}
}
