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

import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.properties.EnumProperty
import java.util.EnumMap

/**
 * 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) {
	HORIZONTAL(
		BlockRotation.NORTH,
		BlockRotation.SOUTH,
		BlockRotation.WEST,
		BlockRotation.EAST,
	),
	DIRECTIONAL(
		BlockRotation.DOWN,
		BlockRotation.UP,
		BlockRotation.NORTH,
		BlockRotation.SOUTH,
		BlockRotation.WEST,
		BlockRotation.EAST,
	),
	DIRECTIONAL_WITH_ROTATION(
		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)
	 */
	FULL(
		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,
	),

	NONE(BlockRotation.NORTH);

	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.entries) {
			oneDirection[direction] = possibleValues.firstOrNull { it.front == direction }
				?: possibleValues.first()

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

			for (direction2 in Direction.entries) {
				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]!!
	}
}
