/*
 *
 * Keeblarcraft
 *
 * This is the primary server side "main" object that is referenced by Fabric. This is where everything is setup for the mod
 * and a very important class. Please becareful as you add to it
 *
*/

// color colour

package jesse.keeblarcraft;

import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.kyrptonaught.customportalapi.api.CustomPortalBuilder;
import net.minecraft.block.Blocks;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.util.Identifier;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.BankMgr.BankManager;
import jesse.keeblarcraft.Commands.CustomCommandManager;
import jesse.keeblarcraft.ConfigMgr.SQLUnitTest;
import jesse.keeblarcraft.CustomBlocks.BlockList;
import jesse.keeblarcraft.CustomBlocks.BlockEntities.BlockEntityRegistration;
import jesse.keeblarcraft.CustomItems.ItemManager;
import jesse.keeblarcraft.EventMgr.DimensionLoadingEvent;
import jesse.keeblarcraft.EventMgr.PlayerJoinListener;
import jesse.keeblarcraft.EventMgr.ServerTickListener;
import jesse.keeblarcraft.GuiMgr.ScreenHandlerRegistration;
import jesse.keeblarcraft.GuiMgr.TreeHandler;
import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION;
import jesse.keeblarcraft.Utils.Setup;

public class Keeblarcraft implements ModInitializer {
    public static String MOD_ID = "keeblarcraft";
    public static final Logger LOGGER = LoggerFactory.getLogger("keeblarcraft");

    // May be moved in future; but is the universal TREE_HANDLER call for at least the tree gui. It's possible it can get a more
    // generic name in the future after the tree gui is done; however until then it will remain TREE_HANDLER.
    public static final ScreenHandlerType<TreeHandler> TREE_HANDLER = Registry.register(Registries.SCREEN_HANDLER,
                                                                    Identifier.of(Keeblarcraft.MOD_ID, "tree_gui"),
                                                                    new ScreenHandlerType<>(TreeHandler::new, FeatureSet.empty()));

    // public static final Block MAGIC_CHEST_BLOCK = Registry.register(Registries.BLOCK, Identifier.of(Keeblarcraft.MOD_ID, "magic_chest_block"),
    //     new MagicChestBlock(AbstractBlock.Settings.copy(Blocks.CHEST)));

    // public static final BlockEntityType<MagicChestBlockEntity> MAGIC_CHEST_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE,
    // Identifier.of(Keeblarcraft.MOD_ID, "magic_chest_block_entity"), BlockEntityType.Builder.create(MagicChestBlockEntity::new, MAGIC_CHEST_BLOCK).build());

    CustomCommandManager cmdMgr = new CustomCommandManager();
    Setup setup = Setup.GetInstance();

    @Override
    public void onInitialize() {
        if (setup != null) {
            try {
                // Run setup. If setup fails; it throws SETUP_FAILED_EXCEPTION
                LOGGER.info("Running setup");
                setup.RunSetup();

                /// TODO: Move callbacks somewhere else
                ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
                    System.out.println("ServerPlayConnectionEvents.JOIN called");
                    PlayerJoinListener.GetInstance().HandleServerJoinEvent(handler, sender, server);
                });

                ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
                    var player = handler.player;
                    Keeblarcraft.LOGGER.info("Player " + player.getName() + " has logged out. Deleting tree...");

                    if (AttributeMgr.activeTrees.containsKey(player.getUuidAsString()) == true) {
                        AttributeMgr.activeTrees.remove(player.getUuidAsString());
                    }
                });

                ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, origin, destination) -> {
                    System.out.println("Calling back...");
                    DimensionLoadingEvent.GetInstance().HandleWorldMove(player, origin, destination);
                });

                ServerLifecycleEvents.SERVER_STOPPING.register((server) -> {
                    // Stuff here
                    System.out.println("SERVER_STOPPING callback called.");
                    DimensionLoadingEvent.GetInstance().SaveInventories();
                });

                ServerEntityEvents.ENTITY_LOAD.register((entity, world) -> {
                    // System.out.println("ENTITY LOAD EVENT INFORMATION");
                    // System.out.println("Name: " + entity.getEntityName());
                    // System.out.println("World: " + world.asString());
                    // System.out.println("COORDS: " + entity.getX() + " " + entity.getY() + " " + entity.getZ());
                    // System.out.println("TYPE: " + entity.getType());
                    // System.out.println("SPAWN GROUP: " + entity.getType().getSpawnGroup().asString());
                    // System.out.println("Is hostile? " + (entity instanceof HostileEntity ? "YES":"NO"));
                });

                // Initialize our ticks!!
                ServerTickListener.InitializeServerTicks();

                // Run command registrations from the command manager
                LOGGER.info("\033[34m Running command registration \033[0m");
                cmdMgr.RegisterCustomCommands();

                // Register attributes
                AttributeMgr.RegisterAttributes();

                // Register the banking system
                BankManager.GetInstance().InitializeBanks();

                System.out.println("Attempting SQL Registration call");

                SQLUnitTest sqlTests = new SQLUnitTest();
                sqlTests.RunTests();

                /// THE BELOW ITEMS MUST BE DONE LAST IN THE STEPS
                // Register items
                ItemManager.RegisterAllItems();

                // Register blocks
                BlockList.RegisterBlocks();
                BlockEntityRegistration.RegisterBlockEntities();

                // World generation

                // Custom portal generator
                System.out.println("BUILDING CUSTOM PORTAL");
                CustomPortalBuilder.beginPortal()
                .frameBlock(Blocks.GOLD_BLOCK)
                .lightWithItem(Items.ENDER_EYE)
                .destDimID(new Identifier(Keeblarcraft.MOD_ID, "keeblarcraftdim"))
                .tintColor(234, 183, 8)
                .registerPortal();

                // Screen handlers
                ScreenHandlerRegistration.registerScreenHandlers();


            } catch (SETUP_FAILED_EXCEPTION e) {
                Keeblarcraft.LOGGER.error("ERROR. Setup failed to initialize environment. Mod likely does not have read/write permissions inside area. Mod will now close out.");
                e.printStackTrace();
            }
        } else {
            // Program exit. Dual definition of setup somehow happened!
            Keeblarcraft.LOGGER.error("Dual definition of singleton attempted! Out of order initialization? How did this even happen?");
        }
    }
}