package org.cyclops.cyclopscore.config.configurabletypeaction;

import com.google.common.collect.Lists;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.color.IBlockColor;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.commons.lang3.tuple.Pair;
import org.cyclops.cyclopscore.config.extendedconfig.BlockConfig;
import org.cyclops.cyclopscore.helper.MinecraftHelpers;

import javax.annotation.Nullable;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * The action used for {@link BlockConfig}.
 * @author rubensworks
 * @see ConfigurableTypeAction
 */
public class BlockAction extends ConfigurableTypeActionForge<BlockConfig, Block> {

    private static final List<BlockConfig> MODEL_ENTRIES = Lists.newArrayList();

    static {
        MinecraftForge.EVENT_BUS.register(BlockAction.class);
    }

    /**
     * Registers a block and its optional item block.
     * @param itemBlockConstructor The optional item block constructor.
     * @param config The config.
     * @param callback A callback that will be called when the entry is registered.
     */
    public static void register(@Nullable BiFunction<BlockConfig, Block, ? extends Item> itemBlockConstructor, BlockConfig config, @Nullable Callable<?> callback) {
        register(config, itemBlockConstructor == null ? callback : null); // Delay onForgeRegistered callback until item has been registered if one is applicable
        if(itemBlockConstructor != null) {
            FMLJavaModLoadingContext.get().getModEventBus().addListener((RegistryEvent.Register<Item> event) -> {
                if (event.getRegistry() == ForgeRegistries.ITEMS) {
                    Item itemBlock = itemBlockConstructor.apply(config, config.getInstance());
                    if (itemBlock.getRegistryName() == null) {
                        itemBlock.setRegistryName(new ResourceLocation(config.getMod().getModId(), config.getNamedId()));
                    }
                    event.getRegistry().register(itemBlock);
                    config.setItemInstance(itemBlock);
                    try {
                        if (callback != null) {
                            callback.call();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    @Override
    public void onRegisterForge(BlockConfig eConfig) {
        // Register block and set creative tab.
        register(eConfig.getItemConstructor(), eConfig, () -> {
            eConfig.onForgeRegistered(); // Manually call after item has been registered
            this.polish(eConfig);
            return null;
        });

        if (MinecraftHelpers.isClientSide()) {
            ItemAction.handleItemModel(eConfig);
        }
    }

    @OnlyIn(Dist.CLIENT)
    @SubscribeEvent
    public static void onModelRegistryLoad(ModelRegistryEvent event) {
        for (BlockConfig config : MODEL_ENTRIES) {
            Pair<ModelResourceLocation, ModelResourceLocation> resourceLocations = config.registerDynamicModel();
            config.dynamicBlockVariantLocation = resourceLocations.getLeft();
            config.dynamicItemVariantLocation  = resourceLocations.getRight();
        }

    }

    public static void handleDynamicBlockModel(BlockConfig extendedConfig) {
        MODEL_ENTRIES.add(extendedConfig);
    }

    protected void polish(BlockConfig config) {
        Block block = config.getInstance();
        if(MinecraftHelpers.isClientSide()) {
            IBlockColor blockColorHandler = config.getBlockColorHandler();
            if (blockColorHandler != null) {
                Minecraft.getInstance().getBlockColors().register(blockColorHandler, block);
            }
        }
    }
}

@@ -269,37 +269,27 @@
 r.model.
-ModelResourceLocation
+IBakedModel
 ;%0Aimport
@@ -307,22 +307,51 @@
 aft.
-item.BlockItem
+client.renderer.model.ModelResourceLocation
 ;%0Aim
@@ -520,16 +520,71 @@
 OnlyIn;%0A
+import net.minecraftforge.client.event.ModelBakeEvent;%0A
 import n
@@ -664,126 +664,22 @@
 rge.
-common.MinecraftForge;%0Aimport net.minecraftforge.event.RegistryEvent;%0Aimport net.minecraftforge.eventbus.api.Subscribe
+event.Registry
 Even
@@ -846,16 +846,82 @@
 e.Pair;%0A
+import org.cyclops.cyclopscore.client.model.IDynamicModelElement;%0A
 import o
@@ -1171,44 +1171,8 @@
 ion;
-%0Aimport java.util.function.Function;
 %0A%0A/*
@@ -1454,32 +1454,36 @@
 tatic %7B%0A        
+if (
 MinecraftForge.E
@@ -1479,52 +1479,254 @@
 raft
-Forge.EVENT_BUS.register(BlockAction.class);
+Helpers.isClientSide()) %7B%0A            FMLJavaModLoadingContext.get().getModEventBus().addListener(BlockAction::onModelRegistryLoad);%0A            FMLJavaModLoadingContext.get().getModEventBus().addListener(BlockAction::onModelBakeEvent);%0A        %7D
 %0A   
@@ -3749,28 +3749,8 @@
 NT)%0A
-    @SubscribeEvent%0A
     
@@ -4144,24 +4144,543 @@
 ;%0A        %7D%0A
+    %7D%0A%0A    @OnlyIn(Dist.CLIENT)%0A    public static void onModelBakeEvent(ModelBakeEvent event)%7B%0A        for (BlockConfig config : MODEL_ENTRIES) %7B%0A            IDynamicModelElement dynamicModelElement = (IDynamicModelElement) config.getInstance();%0A            IBakedModel dynamicModel = dynamicModelElement.createDynamicModel();%0A            event.getModelRegistry().put(config.dynamicBlockVariantLocation, dynamicModel);%0A            event.getModelRegistry().put(config.dynamicItemVariantLocation, dynamicModel);%0A        %7D
 %0A    %7D%0A%0A    

Fix IDynamicModelElement not being handled on blocks