package ru.dbotthepony.mc.otm.data

import com.google.gson.JsonObject
import com.mojang.datafixers.util.Pair
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.DynamicOps
import com.mojang.serialization.JsonOps
import io.netty.buffer.UnpooledByteBufAllocator
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.item.crafting.Recipe
import net.minecraft.world.item.crafting.RecipeSerializer
import java.nio.ByteBuffer

data class RecipePair<R : Recipe<*>>(val recipe: R, val data: JsonObject)

fun <R : Recipe<*>> RecipeSerializer<R>.codec(context: Codec2RecipeSerializer<*>.Context): Codec<RecipePair<R>> {
	return object : Codec<RecipePair<R>> {
		override fun <T : Any> encode(input: RecipePair<R>, ops: DynamicOps<T>, prefix: T): DataResult<T> {
			if (context.isNetwork) {
				val buffer = FriendlyByteBuf(UnpooledByteBufAllocator.DEFAULT.heapBuffer())
				buffer.writeResourceLocation(input.recipe.id)
				toNetwork(buffer, input.recipe)
				buffer.writerIndex(0)
				buffer.readerIndex(0)
				val array = ByteBuffer.allocate(buffer.readableBytes())
				buffer.readBytes(array)
				array.position(0)
				return DataResult.success(ops.createByteList(array))
			} else {
				return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.data))
			}
		}

		override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<RecipePair<R>, T>> {
			if (context.isNetwork) {
				return ops.getByteBuffer(input).map {
					it.position(0)
					val buffer = FriendlyByteBuf(UnpooledByteBufAllocator.DEFAULT.heapBuffer())
					buffer.writeBytes(it)
					buffer.writerIndex(0)
					buffer.readerIndex(0)
					Pair(RecipePair(fromNetwork(buffer.readResourceLocation(), buffer)!!, JsonObject()), ops.empty())
				}
			} else {
				val getJson = ops.convertTo(JsonOps.INSTANCE, input) as JsonObject
				return DataResult.success(Pair(RecipePair(fromJson(context.id, getJson), getJson), ops.empty()))
			}
		}
	}
}
