package ru.dbotthepony.mc.otm.data.condition

import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
import ru.dbotthepony.mc.otm.capability.itemsStream
import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.data.get
import ru.dbotthepony.mc.otm.registry.MLootItemConditions

data class ItemInInventoryCondition(
	val item: ItemStack,
	val matchDamage: Boolean = false,
	val matchNBT: Boolean = false,
	val matchCosmetics: Boolean = true,
) : LootItemCondition, LootItemCondition.Builder {
	override fun test(t: LootContext): Boolean {
		val matches = t[LootContextParams.LAST_DAMAGE_PLAYER]?.itemsStream(matchCosmetics)?.filter {
			if (it.isEmpty) {
				return@filter false
			}

			if (matchDamage && matchNBT) {
				it.item == item.item && it.tag == item.tag && it.damageValue == item.damageValue
			} else if (matchDamage) {
				it.item == item.item && it.damageValue == item.damageValue
			} else if (matchNBT) {
				it.item == item.item && it.tag == item.tag
			} else {
				it.item == item.item
			}
		} ?: return false

		var count = 0

		for (match in matches) {
			count += match.count

			if (count >= item.count) {
				return true
			}
		}

		return false
	}

	override fun getType(): LootItemConditionType {
		return MLootItemConditions.ITEM_IN_INVENTORY
	}

	override fun build(): LootItemCondition {
		return this
	}

	companion object {
		val SERIALIZER = Codec2Serializer<ItemInInventoryCondition>(
			RecordCodecBuilder.create {
				it.group(
					ItemStack.CODEC.fieldOf("item").forGetter(ItemInInventoryCondition::item),
					Codec.BOOL.optionalFieldOf("matchDamage", false).forGetter(ItemInInventoryCondition::matchDamage),
					Codec.BOOL.optionalFieldOf("matchNBT", false).forGetter(ItemInInventoryCondition::matchNBT),
					Codec.BOOL.optionalFieldOf("matchCosmetics", false).forGetter(ItemInInventoryCondition::matchCosmetics),
				).apply(it, ::ItemInInventoryCondition)
			}
		)
	}
}
