package ru.dbotthepony.mc.otm.item

import net.minecraft.ChatFormatting
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.stats.Stats
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent
import net.neoforged.neoforge.common.util.TriState
import net.neoforged.neoforge.event.entity.player.ItemEntityPickupEvent
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.drive.DrivePool
import ru.dbotthepony.mc.otm.capability.drive.ItemMatteryDrive
import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.isServerThread
import ru.dbotthepony.mc.otm.registry.CapabilitiesRegisterListener
import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
import java.math.BigInteger
import java.util.*

class PortableCondensationDriveItem(capacity: Int) : Item(Properties().stacksTo(1)), CapabilitiesRegisterListener {
	val capacity: BigInteger = capacity.toBigInteger()

	override fun appendHoverText(
		stack: ItemStack,
		p_339594_: TooltipContext,
		p_41423_: MutableList<Component>,
		p_41424_: TooltipFlag
	) {
		super.appendHoverText(stack, p_339594_, p_41423_, p_41424_)

		if (stack.has(MDataComponentTypes.CONDENSATION_DRIVE_UUID)) {
			p_41423_.add(TextComponent(stack[MDataComponentTypes.CONDENSATION_DRIVE_UUID].toString()).withStyle(ChatFormatting.GRAY))
		}
	}

	override fun registerCapabilities(event: RegisterCapabilitiesEvent) {
		event.registerItem(MatteryCapability.CONDENSATION_DRIVE, { o, _ ->
			if (!o.has(MDataComponentTypes.CONDENSATION_DRIVE_UUID)) {
				o[MDataComponentTypes.CONDENSATION_DRIVE_UUID] = UUID.randomUUID()
			}

			if (!isServerThread()) {
				return@registerItem ItemMatteryDrive.DUMMY
			}

			DrivePool.get(o[MDataComponentTypes.CONDENSATION_DRIVE_UUID]!!, { tag: CompoundTag?, lookup ->
				val drive = ItemMatteryDrive(capacity, o[MDataComponentTypes.CONDENSATION_DRIVE_UUID]!!)
				drive.deserializeNBT(tag!!, lookup)
				return@get drive
			}, { ItemMatteryDrive(capacity, o[MDataComponentTypes.CONDENSATION_DRIVE_UUID]!!) })
		}, this)
	}

	fun getFilterSettings(item: ItemStack): ItemFilter {
		return item.getOrDefault(MDataComponentTypes.ITEM_FILTER, EMPTY_FILTER)
	}

	fun setFilterSettings(item: ItemStack, filter: ItemFilter) {
		item.set(MDataComponentTypes.ITEM_FILTER, filter)
	}

	@Suppress("unused")
	companion object {
		const val MAX_FILTERS = 4 * 3
		private val EMPTY_FILTER = ItemFilter(MAX_FILTERS)

		fun onPickupEvent(event: ItemEntityPickupEvent.Pre) {
			if (event.itemEntity.owner != null && event.itemEntity.owner != event.player && event.itemEntity.age < 200 || event.itemEntity.item.isEmpty) {
				return
			}

			var amount = event.itemEntity.item.count
			val item = event.itemEntity.item.item

			for (stack in event.player.inventory.items) {
				val drive = stack.item

				if (drive is PortableCondensationDriveItem) {
					var doBreak = false

					stack.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let {
						val filter = stack[MDataComponentTypes.ITEM_FILTER] ?: ItemFilter.EMPTY

						if (filter.match(event.itemEntity.item)) {
							val copy = event.itemEntity.item.copy()
							val remaining = (it as ItemMatteryDrive).insertStack(event.itemEntity.item, false)

							if (remaining.count == event.itemEntity.item.count) {
								return@let
							}

							copy.count -= remaining.count
							event.setCanPickup(TriState.FALSE)
							// TODO
							// EventHooks.firePlayerItemPickupEvent(event.entity, event.item, copy)

							if (remaining.count > 0) {
								event.itemEntity.item.count = remaining.count
								event.player.take(event.itemEntity, amount - remaining.count)

								event.player.awardStat(Stats.ITEM_PICKED_UP.get(item), amount - remaining.count)
								event.player.onItemPickup(event.itemEntity)

								amount = remaining.count
							} else {
								event.player.take(event.itemEntity, amount)

								event.player.awardStat(Stats.ITEM_PICKED_UP.get(item), amount)
								event.player.onItemPickup(event.itemEntity)

								event.itemEntity.discard()
								doBreak = true
							}
						}
					}

					if (doBreak) return
				}
			}
		}
	}
}
