package ru.dbotthepony.mc.otm.datagen.recipes

import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.advancements.critereon.InventoryChangeTrigger
import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.advancements.critereon.MinMaxBounds
import net.minecraft.data.DataGenerator
import net.minecraft.data.recipes.FinishedRecipe
import net.minecraft.data.recipes.RecipeBuilder
import net.minecraft.data.recipes.RecipeProvider
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.util.valueproviders.ConstantFloat
import net.minecraft.util.valueproviders.FloatProvider
import net.minecraft.world.item.Item
import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.level.ItemLike
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe
import java.util.LinkedList
import java.util.function.Consumer
import java.util.stream.Stream

private typealias RecipeBuilderCallback = (MatteryRecipeProvider, consumer: Consumer<FinishedRecipe>) -> Unit

fun has(p_176521_: MinMaxBounds.Ints, p_176522_: ItemLike): InventoryChangeTrigger.TriggerInstance {
	return inventoryTrigger(ItemPredicate.Builder.item().of(p_176522_).withCount(p_176521_).build())
}

fun has(p_125978_: ItemLike): InventoryChangeTrigger.TriggerInstance {
	return inventoryTrigger(ItemPredicate.Builder.item().of(p_125978_).build())
}

fun has(p_125976_: TagKey<Item>): InventoryChangeTrigger.TriggerInstance {
	return inventoryTrigger(ItemPredicate.Builder.item().of(p_125976_).build())
}

fun inventoryTrigger(vararg p_126012_: ItemPredicate): InventoryChangeTrigger.TriggerInstance {
	return InventoryChangeTrigger.TriggerInstance(
		ContextAwarePredicate.ANY,
		MinMaxBounds.Ints.ANY,
		MinMaxBounds.Ints.ANY,
		MinMaxBounds.Ints.ANY,
		p_126012_
	)
}

fun <T : RecipeBuilder> T.unlockedBy(item: ItemLike): T {
	val location = item.asItem().registryName!!
	unlockedBy("has_${location.namespace}_${location.path}", has(item))
	return this
}

fun <T : RecipeBuilder> T.unlockedBy(item: Stream<out ItemLike>): T {
	for (value in item) {
		unlockedBy(value)
	}

	return this
}

fun <T : RecipeBuilder> T.unlockedBy(item: TagKey<Item>): T {
	unlockedBy("has_${item.location.namespace}_${item.location.path}", has(item))
	return this
}

class MatteryRecipeProvider(generatorIn: DataGenerator) : RecipeProvider(generatorIn.packOutput) {
	private val callbacks = LinkedList<RecipeBuilderCallback>()

	fun exec(callback: RecipeBuilderCallback): MatteryRecipeProvider {
		callbacks.add(callback)
		return this
	}

	override fun buildRecipes(callback: Consumer<FinishedRecipe>) {
		for (lambda in callbacks) {
			lambda(this, callback)
		}
	}

	fun plate(id: String, count: Int = 1, workTicks: Int = 200, experience: FloatProvider = ConstantFloat.ZERO) {
		exec { _, consumer ->
			consumer.accept(PlatePressShallowFinishedRecipe(
				modLocation("plates/$id"),
				ResourceLocation("forge", "ingots/$id"),
				ResourceLocation("forge", "plates/$id"),
				count,
				workTicks,
				experience = experience
			))
		}
	}

	fun plate(id: String, ingredient: Ingredient, result: Ingredient, count: Int = 1, workTicks: Int = 200, experience: FloatProvider = ConstantFloat.ZERO) {
		exec { it, callback ->
			callback.accept(PlatePressFinishedRecipe(PlatePressRecipe(modLocation("plate_$id"), ingredient, result, count, workTicks, experience = experience)))
		}
	}
}
