package mezz.jei.startup;

import java.io.File;
import java.util.List;
import java.util.function.Predicate;

import net.minecraftforge.fml.client.event.ConfigChangedEvent;
import net.minecraftforge.fml.loading.FMLPaths;
import net.minecraftforge.client.event.RecipesUpdatedEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.resource.IResourceType;
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
import net.minecraft.client.Minecraft;
import net.minecraft.client.network.play.ClientPlayNetHandler;
import net.minecraft.network.NetworkManager;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourceManager;

import com.google.common.base.Preconditions;
import mezz.jei.Internal;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.constants.ModIds;
import mezz.jei.api.helpers.IModIdHelper;
import mezz.jei.config.BookmarkConfig;
import mezz.jei.config.ClientConfig;
import mezz.jei.config.EditModeConfig;
import mezz.jei.config.IEditModeConfig;
import mezz.jei.config.IngredientFilterConfig;
import mezz.jei.config.KeyBindings;
import mezz.jei.config.ModIdFormattingConfig;
import mezz.jei.config.WorldConfig;
import mezz.jei.events.EventBusHelper;
import mezz.jei.events.PlayerJoinedWorldEvent;
import mezz.jei.gui.overlay.IngredientListOverlay;
import mezz.jei.gui.textures.Textures;
import mezz.jei.ingredients.ForgeModIdHelper;
import mezz.jei.runtime.JeiRuntime;
import mezz.jei.util.AnnotatedInstanceUtil;
import mezz.jei.util.ErrorUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class ClientLifecycleHandler {
	private final Logger LOGGER = LogManager.getLogger();
	private final JeiStarter starter = new JeiStarter();
	private final Textures textures;
	private final ClientConfig clientConfig;
	private final BookmarkConfig bookmarkConfig;
	private final ModIdFormattingConfig modIdFormattingConfig;
	private final IngredientFilterConfig ingredientFilterConfig;
	private final WorldConfig worldConfig;
	private final IModIdHelper modIdHelper;
	private final IEditModeConfig editModeConfig;

	public ClientLifecycleHandler(NetworkHandler networkHandler, Textures textures) {
		File jeiConfigurationDir = new File(FMLPaths.CONFIGDIR.get().toFile(), ModIds.JEI_ID);
		if (!jeiConfigurationDir.exists()) {
			try {
				if (!jeiConfigurationDir.mkdir()) {
					throw new RuntimeException("Could not create config directory " + jeiConfigurationDir);
				}
			} catch (SecurityException e) {
				throw new RuntimeException("Could not create config directory " + jeiConfigurationDir, e);
			}
		}
		clientConfig = new ClientConfig(jeiConfigurationDir);
		bookmarkConfig = new BookmarkConfig(jeiConfigurationDir);
		worldConfig = new WorldConfig(jeiConfigurationDir);
		ingredientFilterConfig = new IngredientFilterConfig(clientConfig.getConfig());
		modIdFormattingConfig = new ModIdFormattingConfig(clientConfig.getConfig());
		modIdHelper = new ForgeModIdHelper(clientConfig, modIdFormattingConfig);
		ErrorUtil.setModIdHelper(modIdHelper);
		ErrorUtil.setWorldConfig(worldConfig);
		editModeConfig = new EditModeConfig(jeiConfigurationDir);

		KeyBindings.init();

		clientConfig.onPreInit();
		EventBusHelper.addListener(ConfigChangedEvent.OnConfigChangedEvent.class, event -> {
			modIdFormattingConfig.checkForModNameFormatOverride();
			if (ModIds.JEI_ID.equals(event.getModID())) {
				if (clientConfig.syncAllConfig()) {
					// todo
				}
				if (ingredientFilterConfig.syncConfig()) {
					JeiRuntime runtime = Internal.getRuntime();
					if (runtime != null) {
						IngredientListOverlay ingredientListOverlay = runtime.getIngredientListOverlay();
						ingredientListOverlay.rebuildIngredientFilter();
					}
				}
				if (worldConfig.syncConfig()) {
					// todo
				}
			}
		});
		EventBusHelper.addListener(WorldEvent.Save.class, event -> worldConfig.onWorldSave());
		EventBusHelper.addListener(RecipesUpdatedEvent.class, event -> {
			ClientPlayNetHandler connection = Minecraft.getInstance().getConnection();
			if (connection != null) {
				NetworkManager networkManager = connection.getNetworkManager();
				worldConfig.syncWorldConfig(networkManager);
			}
			onRecipesLoaded();
			EventBusHelper.post(new PlayerJoinedWorldEvent());
		});

		networkHandler.createClientPacketHandler(worldConfig);

		this.textures = textures;
	}

	private void onRecipesLoaded() {
		modIdFormattingConfig.checkForModNameFormatOverride();

		List<IModPlugin> plugins = AnnotatedInstanceUtil.getModPlugins();

		// Reload when resources change
		Minecraft minecraft = Minecraft.getInstance();
		IResourceManager resourceManager = minecraft.getResourceManager();
		if (resourceManager instanceof IReloadableResourceManager) {
			IReloadableResourceManager reloadableResourceManager = (IReloadableResourceManager) resourceManager;
			reloadableResourceManager.addReloadListener(new JeiReloadListener(plugins));
		}
		Preconditions.checkNotNull(textures);
		this.starter.start(plugins, textures, clientConfig, editModeConfig, ingredientFilterConfig, worldConfig, bookmarkConfig, modIdHelper);
	}

	private final class JeiReloadListener implements ISelectiveResourceReloadListener {
		private final List<IModPlugin> plugins;

		private JeiReloadListener(List<IModPlugin> plugins) {
			this.plugins = plugins;
		}

		@Override
		public void onResourceManagerReload(IResourceManager resourceManager, Predicate<IResourceType> resourcePredicate) {
			// check that JEI has been started before. if not, do nothing
			if (starter.hasStarted()) {
				LOGGER.info("Restarting JEI.");
				Preconditions.checkNotNull(textures);
				starter.start(plugins, textures, clientConfig, editModeConfig, ingredientFilterConfig, worldConfig, bookmarkConfig, modIdHelper);
			}
		}
	}
}

@@ -4958,16 +4958,50 @@
 ));%0A%09%09%7D%0A
+%09%09if (minecraft.world != null) %7B%0A%09
 %09%09Precon
@@ -5032,16 +5032,17 @@
 tures);%0A
+%09
 %09%09this.s
@@ -5170,16 +5170,20 @@
 elper);%0A
+%09%09%7D%0A
 %09%7D%0A%0A%09pri
@@ -5616,16 +5616,57 @@
 tarted()
+ && Minecraft.getInstance().world != null
 ) %7B%0A%09%09%09%09

Fix #1772 crash when disconnecting from server with data pack