package jesse.keeblarcraft.EventMgr;

import java.util.HashMap;
import java.util.Map.Entry;

import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.world.dimension.ModDimensions;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;

public class DimensionLoadingEvent {
    private static DimensionLoadingEvent static_inst;

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         GetInstance
    ///
    /// @brief      Static instance getter for this class
    /////////////////////////////////////////////////////////////////////////////
    public static DimensionLoadingEvent GetInstance() {
        if (static_inst == null) {
            static_inst = new DimensionLoadingEvent();
        }

        return static_inst;
    }

    // Helper class to manage the single inventory cache of dimension loading
    private static class InventoryWrapper {
        public HashMap<String, NbtList> inventories = new HashMap<String, NbtList>();
    }

    private static InventoryWrapper iw = new InventoryWrapper();

    private static String CONFIG_LOCATION = "misc/dim_loading_cached_inventories/";
    ConfigManager config = new ConfigManager();

    public DimensionLoadingEvent() {
        // read config
        iw.inventories = config.ReadAllNbtListFromDirectory(CONFIG_LOCATION, NbtElement.COMPOUND_TYPE);
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         HandleWorldMove
    ///
    /// @param[in]  player is the player object
    ///
    /// @param[in]  origin is the FROM destination world
    ///
    /// @param[in]  destination is the TO destination world
    ///
    /// @brief      Callback handler for player world move events on server
    /////////////////////////////////////////////////////////////////////////////
    public void HandleWorldMove(ServerPlayerEntity player, ServerWorld origin, ServerWorld destination) {
        System.out.println("World move event called!");

        // Player is ENTERING the custom dimension; strip their inventory!
        if (destination.getDimensionEntry().matchesKey(ModDimensions.KEEBLAR_DIM_TYPE) && (!iw.inventories.containsKey(player.getUuidAsString()))) {
            // Make sure player is in map. For now we only care about storing OVERWORLD inventory. We DO NOT care about
            // the dimension inventory!
            // if (!iw.inventories.containsKey(player.getUuidAsString())) {
                // Copy the nbt into the list
                NbtList inventoryNbt = new NbtList();
                player.getInventory().writeNbt(inventoryNbt);

                iw.inventories.put(player.getUuidAsString(), inventoryNbt);
                player.getInventory().clear();
            // }
        // Player is LEAVING the custom dimension. Give them their stuff back
        } else if (origin.getDimensionEntry().matchesKey(ModDimensions.KEEBLAR_DIM_TYPE) && iw.inventories.containsKey(player.getUuidAsString())) {
            // if (iw.inventories.containsKey(player.getUuidAsString())) {
                player.getInventory().readNbt(iw.inventories.get(player.getUuidAsString()));
                iw.inventories.remove(player.getUuidAsString());
            // }
        }

        FlashConfig();
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         SaveInventories
    ///
    /// @brief      Flashes the configuration file on disk (call before server exit
    ///             to not lose memory!)
    /////////////////////////////////////////////////////////////////////////////
    public void SaveInventories() {
        System.out.println("Call to save inventories. Flashing IW.Inventories with size " + iw.inventories.size());
        FlashConfig();
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         GetInventories
    ///
    /// @param      Player uuid
    ///
    /// @brief      Gets a player inventory from the map. Calling this action also
    ///             removes the inventory from the stored map so be sure to use
    ///             it if you call it!
    /////////////////////////////////////////////////////////////////////////////
    public NbtList GetInventory(String uuid) {
        NbtList nbt = iw.inventories.get(uuid);
        iw.inventories.remove(uuid);
        return nbt;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         FlashConfig
    ///
    /// @brief      Flashes configuration file to disk
    /////////////////////////////////////////////////////////////////////////////
    public void FlashConfig() {
        try {
            // config.WriteToJsonFile(CONFIG_LOCATION, iw);
            // First, ensure list is size > 0
            for (Entry<String, NbtList> list : iw.inventories.entrySet()) {
                if (list.getValue().size() > 0) {
                    config.WriteNbtListToFile(CONFIG_LOCATION + list.getKey() + ".nbt", list.getKey(), list.getValue());
                }
            }
        } catch (Exception e) {
            System.out.println("Could not flash dimension loading configuration file");
        }
    }
}
