package ru.dbotthepony.mc.otm.entity

import net.minecraft.core.NonNullList
import net.minecraft.network.syncher.EntityDataAccessor
import net.minecraft.network.syncher.EntityDataSerializers
import net.minecraft.network.syncher.SynchedEntityData
import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.vehicle.AbstractMinecartContainer
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.gameevent.GameEvent
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
import ru.dbotthepony.mc.otm.core.position
import ru.dbotthepony.mc.otm.menu.decorative.MinecartCargoCrateMenu
import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.registry.MSoundEvents

class MinecartCargoCrate(
	type: EntityType<*>,
	val color: DyeColor?,
	level: Level,
	x: Double = 0.0,
	y: Double = 0.0,
	z: Double = 0.0
) : AbstractMinecartContainer(type, x, y, z, level) {
	val block = MRegistry.CARGO_CRATES.allBlocks[color] ?: throw NullPointerException("No cargo crate block for color $color!")
	val item = MItems.CARGO_CRATE_MINECARTS[color] ?: throw NullPointerException("No minecart cargo crate item for color $color!")

	private val itemStacksList = NonNullList.withSize(CargoCrateBlockEntity.CAPACITY, ItemStack.EMPTY)

	override fun getItemStacks(): NonNullList<ItemStack> {
		return itemStacksList
	}

	override fun clearItemStacks() {
		for (i in 0 until itemStacksList.size) {
			itemStacksList[i] = ItemStack.EMPTY
		}
	}

	override fun getDropItem(): Item {
		return item
	}

	override fun getMinecartType(): Type {
		return Type.CHEST
	}

	override fun getDefaultDisplayBlockState(): BlockState {
		return block.defaultBlockState().setValue(CargoCrateBlock.IS_OPEN, interactingPlayers > 0)
	}

	override fun getDefaultDisplayOffset(): Int {
		return 8
	}

	override fun getContainerSize(): Int {
		return CargoCrateBlockEntity.CAPACITY
	}

	override fun createMenu(p_38222_: Int, p_38223_: Inventory): AbstractContainerMenu {
		return MinecartCargoCrateMenu(p_38222_, p_38223_, this)
	}

	override fun getPickResult(): ItemStack {
		return ItemStack(item, 1)
	}

	override fun defineSynchedData() {
		super.defineSynchedData()
		entityData.define(INTERACTING_PLAYERS, 0)
	}

	var interactingPlayers by entityData.delegate(INTERACTING_PLAYERS)

	fun onPlayerOpen() {
		if (isRemoved)
			return

		if (interactingPlayers++ == 0) {
			if (!isRemoved) {
				level().playSound(null, this, MSoundEvents.CARGO_CRATE_OPEN, SoundSource.BLOCKS, 1f, 0.8f + level().random.nextFloat() * 0.2f)
				level().gameEvent(GameEvent.CONTAINER_OPEN, position, GameEvent.Context.of(this))
			}
		}
	}

	fun onPlayerClose() {
		if (interactingPlayers <= 0)
			return

		if (--interactingPlayers == 0) {
			if (!isRemoved) {
				level().gameEvent(GameEvent.CONTAINER_CLOSE, position, GameEvent.Context.of(this))
			}
		}
	}

	companion object {
		val INTERACTING_PLAYERS: EntityDataAccessor<Int> = SynchedEntityData.defineId(MinecartCargoCrate::class.java, EntityDataSerializers.INT)
	}
}
