package ru.dbotthepony.mc.otm.item

import net.minecraft.core.BlockSource
import net.minecraft.core.Direction
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior
import net.minecraft.core.dispenser.DispenseItemBehavior
import net.minecraft.tags.BlockTags
import net.minecraft.world.InteractionResult
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.MinecartItem
import net.minecraft.world.item.context.UseOnContext
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.BaseRailBlock
import net.minecraft.world.level.block.DispenserBlock
import net.minecraft.world.level.block.state.properties.RailShape
import net.minecraft.world.level.gameevent.GameEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.entity.MinecartCargoCrate
import ru.dbotthepony.mc.otm.registry.MEntityTypes
import kotlin.math.floor

class MinecartCargoCrateItem(val color: DyeColor?) : Item(Properties().stacksTo(16)) {
	init {
		DispenserBlock.registerBehavior(this, Companion)
	}

	override fun useOn(useOnContext: UseOnContext): InteractionResult {
		val level = useOnContext.level
		val blockpos = useOnContext.clickedPos
		val blockstate = level.getBlockState(blockpos)

		if (!blockstate.`is`(BlockTags.RAILS)) {
			return InteractionResult.FAIL
		}

		val itemstack = useOnContext.itemInHand

		if (!level.isClientSide) {
			val railshape =
				if (blockstate.block is BaseRailBlock)
					(blockstate.block as BaseRailBlock).getRailDirection(blockstate, level, blockpos, null)
				else
					RailShape.NORTH_SOUTH

			val d0 = if (railshape.isAscending) 0.5 else 0.0
			val type = MEntityTypes.CARGO_CRATE_MINECARTS[color] ?: throw NullPointerException("Unable to find minecart entity type for color $color!")
			val entity = MinecartCargoCrate(type, color, level, blockpos.x.toDouble() + 0.5, blockpos.y.toDouble() + 0.0625 + d0, blockpos.z.toDouble() + 0.5)

			if (itemstack.hasCustomHoverName()) {
				entity.customName = itemstack.hoverName
			}

			level.addFreshEntity(entity)
			level.gameEvent(GameEvent.ENTITY_PLACE, blockpos, GameEvent.Context.of(useOnContext.player, level.getBlockState(blockpos.below())))
		}

		if (useOnContext.player?.abilities?.instabuild != true) {
			itemstack.shrink(1)
		}

		return InteractionResult.sidedSuccess(level.isClientSide)
	}

	companion object : DispenseItemBehavior {
		private val default = DefaultDispenseItemBehavior()

		override fun dispense(blockSource: BlockSource, itemStack: ItemStack): ItemStack {
			val direction = blockSource.blockState.getValue(DispenserBlock.FACING)
			val level: Level = blockSource.level
			val x = blockSource.x() + direction.stepX.toDouble() * 1.125
			val y = floor(blockSource.y()) + direction.stepY.toDouble()
			val z = blockSource.z() + direction.stepZ.toDouble() * 1.125
			val blockpos = blockSource.pos.relative(direction)
			val blockstate = level.getBlockState(blockpos)
			val railshape =
				if (blockstate.block is BaseRailBlock)
					(blockstate.block as BaseRailBlock).getRailDirection(blockstate, level, blockpos, null)
				else
					RailShape.NORTH_SOUTH

			val d3 = if (blockstate.`is`(BlockTags.RAILS)) {
				if (railshape.isAscending) {
					0.6
				} else {
					0.1
				}
			} else {
				if (!blockstate.isAir || !level.getBlockState(blockpos.below()).`is`(BlockTags.RAILS)) {
					return default.dispense(blockSource, itemStack)
				}

				val blockstate1 = level.getBlockState(blockpos.below())
				val railshape1 = if (blockstate1.block is BaseRailBlock) blockstate1.getValue((blockstate1.block as BaseRailBlock).shapeProperty) else RailShape.NORTH_SOUTH

				if (direction != Direction.DOWN && railshape1.isAscending) {
					-0.4
				} else {
					-0.9
				}
			}

			val color = (itemStack.item as MinecartCargoCrateItem).color
			val type = MEntityTypes.CARGO_CRATE_MINECARTS[color] ?: throw NullPointerException("Unable to find minecart entity type for color $color!")

			val entity = MinecartCargoCrate(type, color, level, x, y + d3, z)

			if (itemStack.hasCustomHoverName()) {
				entity.customName = itemStack.hoverName
			}

			level.addFreshEntity(entity)
			itemStack.shrink(1)
			return itemStack
		}
	}
}
