package org.cyclops.cyclopscore.helper;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.fluid.EmptyFluid;
import net.minecraft.fluid.Fluid;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.item.crafting.ShapedRecipe;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.registries.ForgeRegistries;

/**
 * Helpers related to recipe serialization.
 * @author rubensworks
 */
public class RecipeSerializerHelpers {

    private static Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();

    public static Ingredient getJsonIngredient(JsonObject json, String key, boolean required) {
        JsonElement element = json.get(key);
        if (element == null) {
            if (required) {
                throw new JsonSyntaxException("Missing " + key + ", expected to find an ingredient object or string value");
            } else {
                return Ingredient.EMPTY;
            }
        } else if (element.isJsonObject()) {
            return Ingredient.deserialize(JSONUtils.getJsonObject(json, key));
        } else if (element.isJsonArray()) {
            return Ingredient.deserialize(JSONUtils.getJsonArray(json, key));
        } else {
            String itemName = JSONUtils.getString(json, key);
            ResourceLocation resourcelocation = new ResourceLocation(itemName);
            return Ingredient.fromStacks(new ItemStack(Registry.ITEM.getValue(resourcelocation)
                    .orElseThrow(() -> new JsonSyntaxException("Item: " + itemName + " does not exist"))));
        }
    }

    public static ItemStack getJsonItemStackOrTag(JsonObject json, boolean required) {
        if (json.has("tag")) {
            return getJsonItemStackFromTag(json, "tag");
        }
        return getJsonItemStack(json, "item", required);
    }

    public static ItemStack getJsonItemStack(JsonObject json, String key, boolean required) {
        JsonElement element = json.get(key);
        if (element == null) {
            if (required) {
                throw new JsonSyntaxException("Missing " + key + ", expected to find an item object or string value");
            } else {
                return ItemStack.EMPTY;
            }
        } else if (element.isJsonObject()) {
            return ShapedRecipe.deserializeItem(JSONUtils.getJsonObject(json, key));
        } else {
            String itemName = JSONUtils.getString(json, key);
            ResourceLocation resourcelocation = new ResourceLocation(itemName);
            return new ItemStack(Registry.ITEM.getValue(resourcelocation)
                    .orElseThrow(() -> new JsonSyntaxException("Item: " + itemName + " does not exist")));
        }
    }

    public static ItemStack getJsonItemStackFromTag(JsonObject json, String key) {
        ItemStack[] matchingStacks = Ingredient.deserialize(JSONUtils.getJsonObject(json, key)).getMatchingStacks();
        if (matchingStacks.length == 0) {
            throw new IllegalStateException("No tag value found for " + key + " does not exist");
        }
        return matchingStacks[0];
    }

    public static FluidStack deserializeFluidStack(JsonObject json, boolean readNbt) {
        if (json.has("data")) {
            throw new JsonParseException("Disallowed data tag found");
        }

        // Read Fluid
        String fluidName = JSONUtils.getString(json, "fluid");
        ResourceLocation resourcelocation = new ResourceLocation(fluidName);
        Fluid fluid = ForgeRegistries.FLUIDS.getValue(resourcelocation);
        if (fluid instanceof EmptyFluid) {
            throw new JsonParseException("Unknown fluid '" + fluidName + "'");
        }

        // Read NBT
        CompoundNBT tag = null;
        if (readNbt && json.has("nbt")) {
            try {
                JsonElement element = json.get("nbt");
                if (element.isJsonObject()) {
                    tag = JsonToNBT.getTagFromJson(GSON.toJson(element));
                } else {
                    tag = JsonToNBT.getTagFromJson(JSONUtils.getString(element, "nbt"));
                }
            } catch (CommandSyntaxException e) {
                throw new JsonSyntaxException("Invalid NBT Entry: " + e.toString());
            }
        }

        // Read amount
        int amount = FluidHelpers.BUCKET_VOLUME;
        if (json.has("amount")) {
            amount = JSONUtils.getInt(json, "amount");
        }

        return new FluidStack(fluid, amount, tag);
    }

    public static FluidStack getJsonFluidStack(JsonObject json, String key, boolean required) {
        JsonElement element = json.get(key);
        if (element == null) {
            if (required) {
                throw new JsonSyntaxException("Missing " + key + ", expected to find a fluid object or string value");
            } else {
                return FluidStack.EMPTY;
            }
        } else if (element.isJsonObject()) {
            return deserializeFluidStack(JSONUtils.getJsonObject(json, key), true);
        } else {
            String fluidName = JSONUtils.getString(json, key);
            ResourceLocation resourcelocation = new ResourceLocation(fluidName);
            Fluid fluid = ForgeRegistries.FLUIDS.getValue(resourcelocation);
            if (fluid instanceof EmptyFluid) {
                throw new JsonParseException("Unknown fluid '" + fluidName + "'");
            }
            return new FluidStack(fluid, FluidHelpers.BUCKET_VOLUME);
        }
    }

}

@@ -3345,42 +3345,12 @@
 ize(
-JSONUtils.getJsonObject(json, key)
+json
 ).ge
@@ -3510,32 +3510,191 @@
 st%22);%0A        %7D%0A
+        int count = 1;%0A        if (json.has(%22count%22)) %7B%0A            count = json.get(%22count%22).getAsInt();%0A        %7D%0A        matchingStacks%5B0%5D.setCount(count);%0A
         return m

Fix tag-based recipe output not accepting counts