package ru.dbotthepony.mc.otm.recipe

import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.NonNullList
import net.minecraft.core.RegistryAccess
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.valueproviders.ConstantFloat
import net.minecraft.util.valueproviders.FloatProvider
import net.minecraft.world.Container
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.item.crafting.Recipe
import net.minecraft.world.item.crafting.RecipeSerializer
import net.minecraft.world.item.crafting.RecipeType
import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.core.isActuallyEmpty
import ru.dbotthepony.mc.otm.registry.MRecipes
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.data.Codec2RecipeSerializer
import ru.dbotthepony.mc.otm.data.minRange
import ru.dbotthepony.mc.otm.registry.MItems

class PlatePressRecipe(
	private val id: ResourceLocation,
	val input: Ingredient,
	val output: Ingredient,
	val count: Int = 1,
	val workTime: Int = 200,
	val experience: FloatProvider = ConstantFloat.ZERO
) : Recipe<Container> {
	override fun getId(): ResourceLocation {
		return id
	}

	override fun matches(container: Container, p_44003_: Level): Boolean {
		if (isIncomplete)
			return false

		return input.test(container[0])
	}

	fun matches(container: Container, slot: Int): Boolean {
		if (isIncomplete)
			return false

		return input.test(container[slot])
	}

	private val outputStack: ItemStack by lazy {
		if (isIncomplete) {
			ItemStack.EMPTY
		} else {
			val items = output.items
			val bestMatch = items.firstOrNull { it.item.registryName?.namespace == OverdriveThatMatters.MOD_ID } ?: items[0]
			bestMatch.copy().also { it.count = this.count }
		}
	}

	override fun getIngredients(): NonNullList<Ingredient> {
		if (isIncomplete)
			return super.getIngredients()

		return NonNullList.of(Ingredient.EMPTY, input)
	}

	override fun isIncomplete(): Boolean {
		return input.isActuallyEmpty || output.isActuallyEmpty
	}

	override fun assemble(p_44001_: Container, registry: RegistryAccess): ItemStack = outputStack.copy()
	override fun canCraftInDimensions(p_43999_: Int, p_44000_: Int) = true
	override fun getResultItem(registry: RegistryAccess): ItemStack = outputStack

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

	override fun getType(): RecipeType<PlatePressRecipe> = MRecipes.PLATE_PRESS

	override fun getToastSymbol(): ItemStack {
		return ItemStack(MItems.PLATE_PRESS[null]!!)
	}

	fun toFinished() = SERIALIZER.toFinished(this)

	companion object {
		val SERIALIZER = Codec2RecipeSerializer<PlatePressRecipe> { context ->
			RecordCodecBuilder.create {
				it.group(
					context.ingredients.fieldOf("input").forGetter(PlatePressRecipe::input),
					context.ingredients.fieldOf("output").forGetter(PlatePressRecipe::output),
					Codec.INT.minRange(1).optionalFieldOf("count", 1).forGetter(PlatePressRecipe::count),
					Codec.INT.minRange(0).optionalFieldOf("workTime", 200).forGetter(PlatePressRecipe::workTime),
					FloatProvider.CODEC.optionalFieldOf("experience", ConstantFloat.ZERO).forGetter(PlatePressRecipe::experience)
				).apply(it) { a, b, c, d, e -> PlatePressRecipe(context.id, a, b, c, d, e) }
			}
		}
	}
}

