package net.halbear.aotg.utility.Networking;

import net.halbear.aotg.AgeoftheGods;
import net.halbear.aotg.custom.GuiScreens.ForgeWorkbenchGUIScreen;
import net.halbear.aotg.custom.blocks.Forge.ForgeItemRecipe;
import net.halbear.aotg.custom.blocks.Forge.ForgeWorkbenchBlockEntity;
import net.halbear.aotg.custom.blocks.Forge.ForgedAlloyRecipe;
import net.halbear.aotg.registries.ModItems;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.ItemContainerContents;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import net.neoforged.neoforge.network.registration.PayloadRegistrar;

import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

@EventBusSubscriber
public record ForgeWorkbenchGuiButtonHandler(int buttonID, String ResultItem, int x, int y, int z) implements CustomPacketPayload {
    public static final Type<ForgeWorkbenchGuiButtonHandler> TYPE = new Type<>(Identifier.fromNamespaceAndPath(AgeoftheGods.MODID, "forge_workbench_buttons"));
    public static final StreamCodec<RegistryFriendlyByteBuf, ForgeWorkbenchGuiButtonHandler> STREAM_CODEC = StreamCodec.of((RegistryFriendlyByteBuf buffer, ForgeWorkbenchGuiButtonHandler message) -> {
        buffer.writeInt(message.buttonID);
        buffer.writeByteArray(message.ResultItem.getBytes(Charset.defaultCharset()));
        buffer.writeInt(message.x);
        buffer.writeInt(message.y);
        buffer.writeInt(message.z);
    }, (RegistryFriendlyByteBuf buffer) -> new ForgeWorkbenchGuiButtonHandler(buffer.readInt(),new String(buffer.readByteArray(),Charset.defaultCharset()), buffer.readInt(), buffer.readInt(), buffer.readInt()));

    @Override
    public Type<ForgeWorkbenchGuiButtonHandler> type() {
        return TYPE;
    }

    public static Map<String, Item> ItemLookupMap = new HashMap<>();

    public static void handleData(final ForgeWorkbenchGuiButtonHandler message, final IPayloadContext context) {
        if (context.flow() == PacketFlow.SERVERBOUND) {
            ItemLookupMap.clear();
            ForgeItemRecipe.RecipeSet set = ForgeItemRecipe.GetAllValidRecipesFromContainer(ItemStack.EMPTY, ItemStack.EMPTY);
            for(int i = 0; i < set.ItemRecipes().size(); i++){
                ItemLookupMap.put(new ItemStack(set.ItemRecipes().get(i).primaryOutcomeItem()).getItemName().getString(), set.ItemRecipes().get(i).primaryOutcomeItem());
            }
            for(int i = 0; i < set.AlloyRecipes().size(); i++){
                ItemLookupMap.put(new ItemStack(set.AlloyRecipes().get(i).OutcomeItem()).getItemName().getString(), set.AlloyRecipes().get(i).OutcomeItem());
            }
            context.enqueueWork(() -> handleButtonAction(context.player(), message.buttonID, message.x, message.y, message.z, ItemLookupMap.get(message.ResultItem))).exceptionally(e -> {
                context.connection().disconnect(Component.literal(e.getMessage()));
                return null;
            });
        }
    }

    public static ItemStack[] CraftAlloy(ItemStack Pot, Item TargetItem,ItemContainerContents potContents, ForgedAlloyRecipe alloy_recipe){
        ItemStack[] returnVal = new ItemStack[]{ItemStack.EMPTY,ItemStack.EMPTY,ItemStack.EMPTY};
        ItemStack AlloyMetal1 = potContents.getStackInSlot(1);
        ItemStack AlloyMetal2 = potContents.getStackInSlot(2);
        if (alloy_recipe != null) {
            float Ratio = alloy_recipe.AlloyRatio();
            float InRatio = AlloyMetal1.getCount() / (float) AlloyMetal2.getCount();
            int RequiredIngots1 = Ratio < 1 ? 1 : (int) Math.floor(Ratio);
            int RequiredIngots2 = Ratio < 1 ? (int) Math.floor(1 / Ratio) : 1;
            if ((InRatio > Ratio * 0.75 && InRatio < Ratio * 1.25)) {
                int Overfow = AlloyMetal1.getCount() % RequiredIngots1;
                float SetsProduced = (float) AlloyMetal1.getCount() / (float) RequiredIngots1;
                int IngotsProduced = (int)Math.floor((RequiredIngots1 + RequiredIngots2) * SetsProduced) - Overfow;
                int SlagProduced = AlloyMetal1.getCount() + AlloyMetal2.getCount() - IngotsProduced;
                returnVal[0] = (new ItemStack(Items.DECORATED_POT, 1));
                returnVal[1] = (new ItemStack(alloy_recipe.OutcomeItem(), IngotsProduced));
                returnVal[2] = (new ItemStack(ModItems.HARDENED_SLAG.asItem(), SlagProduced));
            } else{
                int SlagProduced = AlloyMetal1.getCount() + AlloyMetal2.getCount();
                returnVal[0] = (new ItemStack(Items.DECORATED_POT, 1));
                returnVal[1] = (ItemStack.EMPTY);
                returnVal[2] = (new ItemStack(ModItems.HARDENED_SLAG.asItem(), SlagProduced));
            }
        } else{
            int SlagProduced = AlloyMetal1.getCount() + AlloyMetal2.getCount();
            returnVal[0] = (new ItemStack(Items.DECORATED_POT, 1));
            returnVal[1] = (ItemStack.EMPTY);
            returnVal[2] = (new ItemStack(ModItems.HARDENED_SLAG.asItem(), SlagProduced));
        }
        return returnVal;
    }

    public static void handleButtonAction(Player entity, int buttonID, int x, int y, int z, Item TargetItem) {
        Level world = entity.level();
        if (!world.getChunkSource().hasChunk(SectionPos.blockToSectionCoord(x), SectionPos.blockToSectionCoord(z)) || TargetItem == null)
            return;
        if (buttonID == 0) {
            AgeoftheGods.LOGGER.debug("ITEM RECIEVED: " + TargetItem.toString());
            BlockPos TargetPos = new BlockPos(x,y,z);
            BlockState blockstate = world.getBlockState(new BlockPos(x,y,z));
            BlockEntity blockEntity = world.getBlockEntity(new BlockPos(TargetPos));
            if(blockEntity instanceof ForgeWorkbenchBlockEntity forgeWorkbenchBlockEntity){
                ItemStack Pot = forgeWorkbenchBlockEntity.getItem(0);
                if(Pot.getItem().equals(Items.DECORATED_POT)) {
                    ItemContainerContents potContents = Pot.get(DataComponents.CONTAINER);
                    if (potContents != null) {
                        boolean hasMarker = potContents.getSlots() == 3 && potContents.getStackInSlot(0).getItem().equals(ModItems.FLUID_INDICATOR_ITEM.asItem());
                        if (hasMarker) {
                            ForgedAlloyRecipe alloy_recipe = ForgedAlloyRecipe.RecipeMap.get(TargetItem);
                            ForgeItemRecipe item_recipe = ForgeItemRecipe.FORGE_ITEM_RECIPE_MAP.get(TargetItem);
                            ItemStack Secondary = forgeWorkbenchBlockEntity.getItem(1);
                            if(alloy_recipe != null){
                                ItemStack[] CraftResult = CraftAlloy(Pot, TargetItem, potContents, alloy_recipe);
                                forgeWorkbenchBlockEntity.setItem(0,CraftResult[0]);
                                forgeWorkbenchBlockEntity.setItem(2,CraftResult[1]);
                                forgeWorkbenchBlockEntity.setItem(4,CraftResult[2]);
                            } else if(item_recipe != null){
                                ItemStack[] CraftResult = CraftAlloy(Pot, TargetItem, potContents, ForgedAlloyRecipe.RecipeMap.get(item_recipe.RequiredItems()[0].asItem()));
                                forgeWorkbenchBlockEntity.setItem(0,CraftResult[0]);
                                ItemStack Alloy = CraftResult[1];
                                ItemStack Slag = CraftResult[2];
                                ItemStack ResultItem = ItemStack.EMPTY;
                                if(Alloy.getItem() == item_recipe.RequiredItems()[0] && Alloy.getCount() >= item_recipe.RequiredItemCounts()[0]
                                        && Secondary.getItem() == item_recipe.RequiredItems()[1] && Secondary.getCount() >= item_recipe.RequiredItemCounts()[1]){
                                    Alloy.setCount(Alloy.getCount() - item_recipe.RequiredItemCounts()[0]);
                                    Secondary.setCount(Secondary.getCount() - item_recipe.RequiredItemCounts()[1]);
                                    ResultItem = new ItemStack(item_recipe.primaryOutcomeItem(), 1);
                                }
                                forgeWorkbenchBlockEntity.setItem(2,ResultItem);
                                forgeWorkbenchBlockEntity.setItem(3,Alloy);
                                forgeWorkbenchBlockEntity.setItem(4,Slag);
                            }
                        }
                    }
                }

            }
        }
    }

    @SubscribeEvent
    public static void registerMessage(final RegisterPayloadHandlersEvent event) {
        final PayloadRegistrar registrar = event.registrar("1.0.0");

        registrar.playToServer(
                ForgeWorkbenchGuiButtonHandler.TYPE,
                ForgeWorkbenchGuiButtonHandler.STREAM_CODEC,
                ForgeWorkbenchGuiButtonHandler::handleData
        );
    }
    @SubscribeEvent
    public static void registerMessage(FMLCommonSetupEvent event) {
        AgeoftheGods.addNetworkMessage(ForgeWorkbenchGuiButtonHandler.TYPE, ForgeWorkbenchGuiButtonHandler.STREAM_CODEC, ForgeWorkbenchGuiButtonHandler::handleData);
    }

}
