/*
 *  Copyright 2025-2026 R3944Realms
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package top.r3944realms.eroticdungeongame.datagen.provider;

import net.minecraft.data.PackOutput;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.data.recipes.RecipeProvider;
import net.minecraft.data.recipes.ShapedRecipeBuilder;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.block.state.properties.WoodType;
import net.minecraftforge.registries.RegistryObject;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.eroticdungeongame.EroticDungeon;
import top.r3944realms.eroticdungeongame.content.block.IWoodTypeBlock;
import top.r3944realms.eroticdungeongame.content.recipe.DungeonRecipeCategory;
import top.r3944realms.eroticdungeongame.core.register.EDGItems;
import top.r3944realms.eroticdungeongame.core.register.EDGRecipeSerializers;
import top.r3944realms.eroticdungeongame.core.register.tag.EDGItemTags;
import top.r3944realms.eroticdungeongame.datagen.builder.DungeonShapedRecipeBuilder;
import top.r3944realms.eroticdungeongame.datagen.builder.DungeonShapelessRecipeBuilder;
import top.r3944realms.eroticdungeongame.datagen.builder.DungeonSpecialRecipeBuilder;
import top.r3944realms.eroticdungeongame.util.ColorContent;
import top.r3944realms.eroticdungeongame.util.WoodTypeHelper;
import top.r3944realms.lib39.util.lang.Pair;

import java.util.function.Consumer;

public class EDGRecipeProvider extends RecipeProvider {
    public EDGRecipeProvider(PackOutput output) {
        super(output);
    }

    @Override
    protected void buildRecipes(@NotNull Consumer<FinishedRecipe> consumer) {

        ShapedRecipeBuilder.shaped(RecipeCategory.MISC, EDGItems.DUNGEON_CRAFTING_TABLE.get())
                .define('#', Items.DIAMOND)
                .define('X', Items.CRAFTING_TABLE)
                .define('Y', Items.IRON_INGOT)
                .pattern("Y#Y")
                .pattern("#X#")
                .pattern("Y#Y")
                .unlockedBy("has_diamond", has(Items.DIAMOND))
                .save(consumer);
        DungeonShapelessRecipeBuilder.shapeless(DungeonRecipeCategory.MISC, EDGItems.FILTER.get())
                .requires(Items.REDSTONE)
                .requires(Items.PAPER)
                .requires(Items.EXPERIENCE_BOTTLE)
                .unlockedBy("has_paper", has(Items.PAPER))
                .save(consumer);
        DungeonShapelessRecipeBuilder.shapeless(DungeonRecipeCategory.TOOLS, EDGItems.DEVICE_KEY.get())
                .requires(Items.IRON_INGOT)
                .requires(Items.STONE)
                .unlockedBy("has_iron_ingot", has(Items.IRON_INGOT))
                .save(consumer);
        DungeonShapelessRecipeBuilder.shapeless(DungeonRecipeCategory.TOOLS, EDGItems.DEVICE_KEY.get())
                .requires(EDGItems.DEVICE_KEY.get())
                .unlockedBy("has_device_key", has(EDGItems.DEVICE_KEY.get()))
                .save(consumer, EroticDungeon.rl("device_key_reset"));
        DungeonShapelessRecipeBuilder.shapeless(DungeonRecipeCategory.TOOLS, EDGItems.END_ROD_LOVE_MACHINE.get())
                .requires(Items.STICKY_PISTON)
                .requires(Items.END_ROD)
                .unlockedBy("has_end_rod", has(Items.END_ROD))
                .save(consumer);
        DungeonShapelessRecipeBuilder.shapeless(DungeonRecipeCategory.TOOLS, EDGItems.LIGHTNING_ROD_LOVE_MACHINE.get())
                .requires(Items.STICKY_PISTON)
                .requires(Items.LIGHTNING_ROD)
                .unlockedBy("has_lightning_rod", has(Items.LIGHTNING_ROD))
                .save(consumer);
        DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.TOOLS, EDGItems.WHIP.get())
                .define('X', Items.LEATHER)
                .define('Y', Items.STICK)
                .pattern("  X")
                .pattern(" X ")
                .pattern("Y  ")
                .unlockedBy("has_leather", has(Items.LEATHER))
                .save(consumer);
        for (ColorContent color : ColorContent.values()) {
            RegistryObject<Item> cuffBedObj = EDGItems.CUFF_BED_ITEMS.get(color);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_COLORFUL_DEVICE, cuffBedObj.get())
                    .define('#', ColorContent.COLOR_WOOL_ITEM_MAP.get(color))
                    .define('X', ItemTags.PLANKS)
                    .define('Y', Items.CHAIN)
                    .define('Z', Items.IRON_INGOT)
                    .pattern("ZYZ")
                    .pattern("###")
                    .pattern("XXX")
                    .group("cuff_bed")
                    .unlockedBy("has_chain", has(Items.CHAIN))
                    .save(consumer);
            Item[] array = EDGItems.CUFF_BED_ITEMS.values().stream().filter(i -> !i.equals(cuffBedObj)).map(RegistryObject::get).toArray(Item[]::new);
            DungeonShapelessRecipeBuilder.shapeless(DungeonRecipeCategory.MAIN_COLORFUL_DEVICE, cuffBedObj.get())
                    .requires(ColorContent.COLOR_DYE_ITEM_MAP.get(color))
                    .requires(Ingredient.of(array))
                    .unlockedBy("has_cuff_bed", has(EDGItemTags.CUFF_BED))
                    .group("dyed_cuff_bed")
                    .save(consumer, EroticDungeon.rl("dyed_"+ cuffBedObj.getId().getPath()));
        }
        for (WoodType woodType : WoodTypeHelper.SUPPORTED_WOOD_TYPES) {
            RegistryObject<Item> rackObj = EDGItems.RACK_ITEMS.get(woodType);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, rackObj.get(), 3)
                    .define('X', Ingredient.of(WoodTypeHelper.getStrippedLogItem(woodType), WoodTypeHelper.getStrippedWoodItem(woodType)))
                    .define('Y', Items.CHAIN)
                    .define('Z', Items.IRON_INGOT)
                    .pattern("ZYZ")
                    .pattern("XXX")
                    .group("rack")
                    .unlockedBy("has_chain", has(Items.CHAIN))
                    .save(consumer);
            RegistryObject<Item> cruxObj = EDGItems.CRUX_ITEMS.get(woodType);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, cruxObj.get(), 3)
                    .define('X', WoodTypeHelper.getPlanksItem(woodType))
                    .define('V', WoodTypeHelper.getSlabItem(woodType))
                    .define('Y', Items.CHAIN)
                    .define('Z', Items.IRON_INGOT)
                    .pattern("VXV")
                    .pattern("ZXZ")
                    .pattern("YXY")
                    .group("crux")
                    .unlockedBy("has_chain", has(Items.CHAIN))
                    .save(consumer);
            RegistryObject<Item> xCrossObj = EDGItems.X_CROSS_ITEMS.get(woodType);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, xCrossObj.get(), 3)
                    .define('X', Ingredient.of(WoodTypeHelper.getStrippedLogItem(woodType), WoodTypeHelper.getStrippedWoodItem(woodType)))
                    .define('Z', Items.IRON_INGOT)
                    .pattern("XZX")
                    .pattern(" X ")
                    .pattern("XZX")
                    .group("x_cross")
                    .unlockedBy("has_chain", has(Items.CHAIN))
                    .save(consumer);
            RegistryObject<Item> petrineCrossObj = EDGItems.PETRINE_CROSS_ITEMS.get(woodType);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, petrineCrossObj.get(), 3)
                    .define('X', WoodTypeHelper.getPlanksItem(woodType))
                    .define('V', WoodTypeHelper.getSlabItem(woodType))
                    .define('Y', Items.CHAIN)
                    .define('Z', Items.IRON_INGOT)
                    .pattern("ZXZ")
                    .pattern("YXY")
                    .pattern("VXV")
                    .group("petrine_cross")
                    .unlockedBy("has_chain", has(Items.CHAIN))
                    .save(consumer);
            RegistryObject<Item> spanishDonkeyObj = EDGItems.SPANISH_DONKEY_ITEMS.get(woodType);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, spanishDonkeyObj.get())
                    .define('X', WoodTypeHelper.getPlanksItem(woodType))
                    .define('V', WoodTypeHelper.getSlabItem(woodType))
                    .define('Y', Items.REDSTONE)
                    .define('Z', Items.STICK)
                    .pattern("VXV")
                    .pattern("ZYZ")
                    .group("spanish_donkey")
                    .unlockedBy("has_redstone", has(Items.REDSTONE))
                    .save(consumer);
            RegistryObject<Item> pilloryObj = EDGItems.PILLORY_ITEMS.get(woodType);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, pilloryObj.get(), 1)
                    .define('X', WoodTypeHelper.getFenceGateItem(woodType))
                    .define('W', WoodTypeHelper.getSlabItem(woodType))
                    .define('Z', WoodTypeHelper.getFenceItem(woodType))
                    .pattern(" X ")
                    .pattern(" W ")
                    .pattern(" Z ")
                    .group("pillory")
                    .unlockedBy("has_slab", has(ItemTags.WOODEN_SLABS))
                    .save(consumer);
            RegistryObject<Item> wallRackObj = EDGItems.WALL_RACK_ITEMS.get(woodType);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, wallRackObj.get(), 3)
                    .define('X', WoodTypeHelper.getLogItem(woodType))
                    .define('Y', WoodTypeHelper.getPlanksItem(woodType))
                    .define('Z', Items.IRON_INGOT)
                    .pattern("Z Z")
                    .pattern("XYX")
                    .group("wall_rack")
                    .unlockedBy("has_redstone", has(Items.REDSTONE))
                    .save(consumer);
            RegistryObject<Item> cuffPoleObj = EDGItems.CUFF_POLE_ITEMS.get(woodType);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, cuffPoleObj.get(), 4)
                    .define('X', WoodTypeHelper.getLogItem(woodType))
                    .define('Y', Items.IRON_INGOT)
                    .pattern("YXY")
                    .pattern(" X ")
                    .group("cuff_pole")
                    .unlockedBy("has_iron_ingot", has(Items.IRON_INGOT))
                    .save(consumer);
            RegistryObject<Item> HangingPostObj = EDGItems.HANGING_POST_ITEMS.get(woodType);
            DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, HangingPostObj.get())
                    .define('X', Ingredient.of(WoodTypeHelper.getStrippedLogItem(woodType), WoodTypeHelper.getStrippedWoodItem(woodType)))
                    .define('Y', Items.CHAIN)
                    .pattern("XXX")
                    .pattern("X Y")
                    .pattern("X  ")
                    .group("hanging_post")
                    .unlockedBy("has_chain", has(Items.CHAIN))
                    .save(consumer);
            for (ColorContent color : ColorContent.values()) {
                RegistryObject<Item> proneBenchObj = EDGItems.PRONE_BENCH_ITEMS.get(Pair.of(color, woodType));
                DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.MAIN_WOODEN_DEVICES, proneBenchObj.get())
                        .define('X', Ingredient.of(WoodTypeHelper.getStrippedLogItem(woodType), WoodTypeHelper.getStrippedWoodItem(woodType)))
                        .define('Y', ColorContent.COLOR_WOOL_ITEM_MAP.get(color))
                        .define('Z', Items.IRON_INGOT)
                        .pattern("ZYZ")
                        .pattern("XXX")
                        .pattern("X X")
                        .group("prone_bench")
                        .unlockedBy("has_wool", has(ItemTags.WOOL))
                        .save(consumer);
                WoodType wood = ((IWoodTypeBlock)((BlockItem) proneBenchObj.get()).getBlock()).getWoodType();
                Item[] array = EDGItems.PRONE_BENCH_ITEMS.values().stream().filter(i -> {
                    WoodType woodType_ = ((IWoodTypeBlock)((BlockItem) i.get()).getBlock()).getWoodType();
                    return woodType_.equals(wood) && !i.equals(proneBenchObj);
                }).map(RegistryObject::get).toArray(Item[]::new);
                DungeonShapelessRecipeBuilder.shapeless(DungeonRecipeCategory.MIXIN_WOODEN_AND_COLOR_DEVICES, proneBenchObj.get())
                        .requires(ColorContent.COLOR_DYE_ITEM_MAP.get(color))
                        .requires(Ingredient.of(array))
                        .unlockedBy("has_prone_bench", has(EDGItemTags.PRONE_BENCH))
                        .group("dyed_prone_bench")
                        .save(consumer, EroticDungeon.rl("dyed_"+ proneBenchObj.getId().getPath()));
            }
        }
        DungeonShapedRecipeBuilder.shaped(DungeonRecipeCategory.METAL_DEVICES, EDGItems.IRON_CAGE_ITEM.get())
                .define('W', Items.IRON_BARS)
                .define('I', Items.IRON_INGOT)
                .pattern("IWI")
                .pattern("WWW")
                .pattern("IWI")
                .group("iron_cage")
                .unlockedBy("has_iron_bars", has(Items.IRON_BARS))
                .save(consumer);
        DungeonSpecialRecipeBuilder.special(EDGRecipeSerializers.DUNGEON_KEY_COPY.get()).save(consumer, "key_copy");
    }
}
