package ru.dbotthepony.mc.otm.recipe

import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException
import net.minecraft.core.NonNullList
import net.minecraft.core.RegistryAccess
import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.inventory.CraftingContainer
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.CraftingBookCategory
import net.minecraft.world.item.crafting.CraftingRecipe
import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.item.crafting.RecipeSerializer
import net.minecraft.world.level.Level
import net.minecraftforge.common.Tags
import ru.dbotthepony.mc.otm.container.stream
import ru.dbotthepony.mc.otm.core.isActuallyEmpty
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.item.tool.ExplosiveHammerItem
import ru.dbotthepony.mc.otm.registry.MItems

class ExplosiveHammerPrimingRecipe(private val _id: ResourceLocation, val payload: Ingredient) : CraftingRecipe {
	override fun isIncomplete(): Boolean {
		return payload.isActuallyEmpty
	}

	override fun getId(): ResourceLocation {
		return _id
	}

	override fun isSpecial(): Boolean {
		return true
	}

	override fun matches(pContainer: CraftingContainer, pLevel: Level): Boolean {
		val result = pContainer.stream().filter { it.isNotEmpty }.toList()
		if (result.size != 3) return false
		return result.any { it.item is ExplosiveHammerItem && !(it.item as ExplosiveHammerItem).isPrimed(it) } &&
				result.any { it.`is`(Tags.Items.GUNPOWDER) } &&
				result.any { payload.test(it) }
	}

	override fun assemble(pContainer: CraftingContainer, registry: RegistryAccess): ItemStack {
		val hammer = pContainer.stream().filter { it.isNotEmpty && it.item is ExplosiveHammerItem }.findAny()
		if (hammer.isEmpty) return ItemStack.EMPTY

		return hammer.orElseThrow().copyWithCount(1).also {
			(it.item as ExplosiveHammerItem).prime(it)
		}
	}

	override fun canCraftInDimensions(pWidth: Int, pHeight: Int): Boolean {
		return pWidth * pHeight >= 3
	}

	override fun getResultItem(registry: RegistryAccess): ItemStack {
		return ItemStack.EMPTY
	}

	override fun getSerializer(): RecipeSerializer<*> {
		return Companion
	}

	override fun category(): CraftingBookCategory {
		return CraftingBookCategory.EQUIPMENT
	}

	override fun getIngredients(): NonNullList<Ingredient> {
		return NonNullList.of(Ingredient.of(), Ingredient.of(MItems.EXPLOSIVE_HAMMER), Ingredient.of(Tags.Items.GUNPOWDER), payload)
	}

	val finishedRecipe = object : FinishedRecipe {
		override fun serializeRecipeData(pJson: JsonObject) {
			pJson["payload"] = payload.toJson()
		}

		override fun getId(): ResourceLocation {
			return _id
		}

		override fun getType(): RecipeSerializer<*> {
			return Companion
		}

		override fun serializeAdvancement(): JsonObject? {
			return null
		}

		override fun getAdvancementId(): ResourceLocation? {
			return null
		}
	}

	companion object : RecipeSerializer<ExplosiveHammerPrimingRecipe> {
		override fun fromJson(pRecipeId: ResourceLocation, pSerializedRecipe: JsonObject): ExplosiveHammerPrimingRecipe {
			return ExplosiveHammerPrimingRecipe(pRecipeId, Ingredient.fromJson(pSerializedRecipe["payload"] ?: throw JsonSyntaxException("Missing `payload` from hammer priming recipe in $pRecipeId")))
		}

		override fun fromNetwork(pRecipeId: ResourceLocation, pBuffer: FriendlyByteBuf): ExplosiveHammerPrimingRecipe {
			return ExplosiveHammerPrimingRecipe(pRecipeId, Ingredient.fromNetwork(pBuffer))
		}

		override fun toNetwork(pBuffer: FriendlyByteBuf, pRecipe: ExplosiveHammerPrimingRecipe) {
			pRecipe.payload.toNetwork(pBuffer)
		}
	}
}
