package me.km;

import java.util.function.Supplier;
import me.kcm.Hooks;
import me.km.blocks.ModBlocks;
import me.km.networking.ModPacketHandler;
import me.km.overrides.ModPlayerList;
import me.km.world.WorldEvents;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.DecoratedFeatureConfig;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.OreFeatureConfig;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder;
import net.minecraftforge.event.world.BiomeLoadingEvent;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;

@Mod.EventBusSubscriber
@Mod("km")
public class KajetansMod {
    public static final String MODID = "km";

    public KajetansMod() {
        ClassLoaderUtils.loadDependencies();

        IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
        bus.addListener(this::init);
        bus.addListener(this::clientInit);
        bus.addListener(this::serverInit);

        MinecraftForge.EVENT_BUS.register(this);
    }

    private void init(FMLCommonSetupEvent e) {
        ModPacketHandler.init();
        MinecraftForge.EVENT_BUS.register(new CommonEvents());
    }

    private void clientInit(FMLClientSetupEvent e) {
        Client.init();
    }

    private void serverInit(FMLDedicatedServerSetupEvent e) {
        MinecraftForge.EVENT_BUS.register(new WorldEvents());
        Hooks.setPlayerListFunction((ds, impl, pd) -> {
            ds.setPlayerList(new ModPlayerList(ds, impl, pd));
        });
    }

    @SubscribeEvent
    public void onServerStart(FMLServerStartingEvent e) {
        if(e.getServer().isDedicatedServer()) {
            Server.onStart((DedicatedServer) e.getServer());
        }
    }

    @SubscribeEvent
    public void onServerStop(FMLServerStoppedEvent e) {
        if(e.getServer().isDedicatedServer()) {
            Server.onStop();
        }
    }

    @SubscribeEvent
    public void onBiomeLoad(BiomeLoadingEvent e) {
        if(findOreBiome(e)) {
            addFeatures(e.getGeneration());
        }
    }

    private static boolean findOreBiome(BiomeLoadingEvent e) {
        for(Supplier<ConfiguredFeature<?, ?>> a : e.getGeneration()
                .getFeatures(GenerationStage.Decoration.UNDERGROUND_ORES)) {
            ConfiguredFeature<?, ?> cf = a.get();
            if(unpack(cf)) {
                return true;
            }
        }
        return false;
    }

    private static boolean unpack(ConfiguredFeature<?, ?> cf) {
        if(cf.config instanceof DecoratedFeatureConfig) {
            return unpack(((DecoratedFeatureConfig) cf.config).feature.get());
        } else if(cf.config instanceof OreFeatureConfig) {
            OreFeatureConfig oreConfig = (OreFeatureConfig) cf.config;
            if(oreConfig.state.getBlock() == Blocks.IRON_ORE) {
                return true;
            }
        }
        return false;
    }

    private static void addOre(BiomeGenerationSettingsBuilder builder, Block ore, int maxCount,
            int spawnTries, int maxHeight) {
        builder.withFeature(GenerationStage.Decoration.UNDERGROUND_ORES, Feature.ORE
                .withConfiguration(
                        new OreFeatureConfig(OreFeatureConfig.FillerBlockType.BASE_STONE_OVERWORLD,
                                ore.getDefaultState(), maxCount))
                .range(maxHeight).square().func_242731_b(spawnTries));
    }

    private static void addFeatures(BiomeGenerationSettingsBuilder builder) {
        addOre(builder, ModBlocks.copperOre, 9, 25, 128);
        addOre(builder, ModBlocks.tinOre, 6, 12, 96);
        addOre(builder, ModBlocks.silverOre, 9, 3, 64);
    }
}
