package jesse.keeblarcraft.EventMgr;

import java.util.HashMap;

import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.AttributeMgr.AttributeTree;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.ConfigMgr.GeneralConfig;
import jesse.keeblarcraft.Utils.DirectionalVec;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;

public class PlayerJoinListener {
    private static PlayerJoinListener static_inst;
    ConfigManager config = new ConfigManager();
    String CACHED_PLAYER_LOGIN_CONFIG = "misc/cached_uuids.json";

    private class CachedUUIDConfig {
        HashMap<String, String> cached_uuids = new HashMap<String, String>();
    }
    CachedUUIDConfig cachedPlayerConfig;

    // Get the static instance for this class
    public static PlayerJoinListener GetInstance() {
        if (static_inst == null) {
            static_inst = new PlayerJoinListener();
        }
        return static_inst;
    }

    public PlayerJoinListener() {
        Boolean existingFile = false;
        cachedPlayerConfig = new CachedUUIDConfig();

        try {
            cachedPlayerConfig = config.GetJsonObjectFromFile(CACHED_PLAYER_LOGIN_CONFIG, CachedUUIDConfig.class);
            existingFile = cachedPlayerConfig != null;
        } catch (Exception e) {
            // intentionally empty
        }

        if (!existingFile) {
            try {
                cachedPlayerConfig = new CachedUUIDConfig();
                config.CreateFile(CACHED_PLAYER_LOGIN_CONFIG);
                FlashCachedConfig();
            } catch (Exception e) {
                System.out.println("Failed to parse or create cached uuid file");
            }
        }
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         HandleServerJoinEvent
    ///
    /// @param[in]  handler is the network handler
    ///
    /// @param[in]  sender is the packet sender
    ///
    /// @param[in]  server is the MinecraftServer instance
    ///
    /// @brief      Callback function for player join event in minecraft server
    /////////////////////////////////////////////////////////////////////////////
    public void HandleServerJoinEvent(ServerPlayNetworkHandler handler, PacketSender sender, MinecraftServer server) {
        var player = handler.player;

        // Handle skill tree map instance
        if (AttributeMgr.activeTrees.containsKey(player.getUuidAsString()) == false) {
            AttributeMgr.activeTrees.put(player.getUuidAsString(), new AttributeTree(player));
        }

        // Handle first time joining events (world spawn teleport, MOTD, etc)
        System.out.println("Running first time login stuff");
        IsFirstTimeLogin(player, server);
        CachePlayersUuid(player.getUuidAsString(), player.getEntityName());
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         IsFirstTimeLogin
    ///
    /// @param[in]  player is the player who is joining
    ///
    /// @param[in]  server is the MinecraftServer instance
    ///
    /// @brief      Check to see if player is first time log-in. If so, we teleport
    ///             them to spawn. This function may be expanded in future
    /////////////////////////////////////////////////////////////////////////////
    private void IsFirstTimeLogin(ServerPlayerEntity player, MinecraftServer server) {
        // Send the MOTD + Spawn in global spawn
        player.sendMessage(Text.of(GeneralConfig.GetInstance().GetMOTD()));
        if (GeneralConfig.GetInstance().IsNewPlayer(player.getUuidAsString())) {
            DirectionalVec coords = GeneralConfig.GetInstance().GetSpawnCoords();
            if (coords != null) {
                for (ServerWorld world : player.getServer().getWorlds()) {
                    if (world.getRegistryKey().toString().equals(coords.world.toString())) {
                        try {
                            player.teleport(world, coords.x, coords.y, coords.z, coords.yaw, coords.pitch);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    public String TryGetPlayerUuidByName(String name) {
        String uuid = "";
        if (cachedPlayerConfig != null && cachedPlayerConfig.cached_uuids.containsKey(name)) {
            uuid = cachedPlayerConfig.cached_uuids.get(name);
        }
        return uuid;
    }

    private void CachePlayersUuid(String uuid, String entityName) {
        if (cachedPlayerConfig.cached_uuids.containsKey(entityName)) {
            return;
        } else {
            cachedPlayerConfig.cached_uuids.put(entityName, uuid);
            FlashCachedConfig();
        }
    }

    private void FlashCachedConfig() {
        try {
            config.WriteToJsonFile(CACHED_PLAYER_LOGIN_CONFIG, cachedPlayerConfig);
        } catch (Exception e) {
            System.out.println("Encountered exception in writing cached uuid file!");
        }
    }
}
