package ru.dbotthepony.mc.otm.block.tech

import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
import ru.dbotthepony.mc.otm.block.MatteryBlock
import ru.dbotthepony.mc.otm.block.entity.tech.EnergyCounterBlockEntity
import ru.dbotthepony.mc.otm.once
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes

class EnergyCounterBlock : MatteryBlock(), EntityBlock {
	override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
		return EnergyCounterBlockEntity(blockPos, blockState)
	}

	override fun <T : BlockEntity?> getTicker(
		level: Level,
		blockState: BlockState,
		blockEntityType: BlockEntityType<T>
	): BlockEntityTicker<T>? {
		if (blockEntityType !== MBlockEntities.ENERGY_COUNTER)
			return null

		if (level.isClientSide)
			return BlockEntityTicker { _, _, _, tile -> if (tile is EnergyCounterBlockEntity) tile.clientTick() }

		return BlockEntityTicker { _, _, _, tile -> if (tile is EnergyCounterBlockEntity) tile.tick() }
	}

	override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
		val inputDir =
			if (context.player != null && context.player!!.isCrouching) context.clickedFace.opposite else context.clickedFace

		val opposite = inputDir.opposite
		var dir: Direction? = null

		for (_dir in context.nearestLookingDirections) {
			if (_dir != inputDir && _dir != opposite) {
				dir = _dir.opposite
				break
			}
		}

		return defaultBlockState().setValue(INPUT_DIRECTION, inputDir).setValue(IF_DIRECTION, dir!!)
	}

	override fun createBlockStateDefinition(p_49915_: StateDefinition.Builder<Block, BlockState>) {
		super.createBlockStateDefinition(p_49915_)
		p_49915_.add(INPUT_DIRECTION, IF_DIRECTION)
	}

	private val SHAPES = HashMap<BlockState, VoxelShape>()

	init {
		for (state in stateDefinition.possibleStates) {
			val input: Direction = state.getValue(INPUT_DIRECTION)
			val iface: Direction = state.getValue(IF_DIRECTION)

			var shape = when (input) {
				Direction.DOWN ->  	BlockShapes.ENERGY_COUNTER_DOWN
				Direction.UP -> 	BlockShapes.ENERGY_COUNTER_UP
				Direction.NORTH -> 	BlockShapes.ENERGY_COUNTER_NORTH
				Direction.SOUTH -> 	BlockShapes.ENERGY_COUNTER_SOUTH
				Direction.WEST -> 	BlockShapes.ENERGY_COUNTER_WEST
				Direction.EAST -> 	BlockShapes.ENERGY_COUNTER_EAST
			}

			if (input === Direction.UP || input === Direction.DOWN) {
				shape = shape.rotateFromNorth(iface)
			} else if (input === Direction.EAST || input === Direction.WEST) {
				when (iface) {
					Direction.DOWN -> shape = shape.rotateAroundX(Math.PI / 2)
					Direction.UP -> shape = shape.rotateAroundX(-Math.PI / 2)
					Direction.NORTH -> { /* уже в нужном положении */ }
					Direction.SOUTH -> shape = shape.rotateAroundX(Math.PI)
					Direction.WEST -> { /* недостижимо */ }
					Direction.EAST -> { /* недостижимо */ }
				}
			} else {
				when (iface) {
					Direction.DOWN -> shape = shape.rotateAroundZ(Math.PI)
					Direction.UP -> { /* уже в нужном положении */ }
					Direction.NORTH -> { /* недостижимо */ }
					Direction.SOUTH -> { /* недостижимо */ }
					Direction.WEST -> shape = shape.rotateAroundZ(Math.PI / 2)
					Direction.EAST -> shape = shape.rotateAroundZ(-Math.PI / 2)
				}
			}

			SHAPES[state] = shape.computeShape()
		}
	}

	override fun getShape(
		blockState: BlockState,
		p_60556_: BlockGetter,
		p_60557_: BlockPos,
		p_60558_: CollisionContext
	): VoxelShape {
		return SHAPES[blockState] ?: super.getShape(blockState, p_60556_, p_60557_, p_60558_)
	}

	companion object {
		@JvmField val INPUT_DIRECTION: EnumProperty<Direction> = EnumProperty.create("input", Direction::class.java)
		@JvmField val IF_DIRECTION: EnumProperty<Direction> = EnumProperty.create("if", Direction::class.java)
	}
}
