package xyz.tbvns.rogue_block.Managers;

import com.esotericsoftware.kryo.kryo5.Kryo;
import com.esotericsoftware.kryo.kryo5.io.*;
import lombok.Data;
import net.minecraft.entity.LivingEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.world.PersistentState;
import net.minecraft.world.PersistentStateManager;
import net.minecraft.world.World;
import org.reflections.Reflections;
import xyz.tbvns.rogue_block.Managers.registeredSavable.PlayerData;
import xyz.tbvns.rogue_block.Packets.Packet;
import xyz.tbvns.rogue_block.Rogue_block;
import xyz.tbvns.rogue_block.Upgrades.Upgrade;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.*;

public class DataManager extends PersistentState {
    //Add thins here if i need global values someday
    //Useful doc: https://fabricmc.net/wiki/tutorial:persistent_states a bit outdated tho
    public HashMap<UUID, PlayerData> players = new HashMap<>();

    static Kryo kryo = new Kryo();
    public static void setup() {
        kryo.setRegistrationRequired(false);
    }

    public static PlayerData readPlayerData(byte[] buffer) {
        ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, 0, 1000);
        buffer = byteBuffer.array();
        Input input = new Input(buffer);
        PlayerData playerData = kryo.readObject(input, PlayerData.class);
        input.close();
        return playerData;
    }

    public static ByteBuffer write(PlayerData object) {
        Output output = new Output(1000);
        kryo.writeObject(output, object);
        ByteBuffer buffer = ByteBuffer.wrap(output.getBuffer());
        output.close();
        return buffer;
    }

    @Override
    public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) {
        NbtCompound playersNbt = new NbtCompound();
        players.forEach((uuid, playerData) -> {
            NbtCompound playerNbt = new NbtCompound();
            playerNbt.putByteArray("rogue_block", write(playerData).array());
            playersNbt.put(uuid.toString(), playerNbt);
        });
        nbt.put("players", playersNbt);
        return nbt;
    }

    public static DataManager createFromNbt(NbtCompound tag, RegistryWrapper.WrapperLookup registryLookup) {
        DataManager dataManager = new DataManager();
        NbtCompound playersNbt = tag.getCompound("players");
        playersNbt.getKeys().forEach(key -> {
            PlayerData playerData = readPlayerData(playersNbt.getCompound(key).getByteArray("rogue_block"));
            if (playerData == null) {
                playerData = new PlayerData();
            }
            UUID uuid = UUID.fromString(key);
            dataManager.players.put(uuid, playerData);
        });
        return dataManager;
    }

    public static PlayerData getPlayerState(LivingEntity player) {
        DataManager serverState = getServerState(player.getWorld().getServer());
        PlayerData playerState = serverState.players.computeIfAbsent(player.getUuid(), uuid -> new PlayerData());
        DataManager state = getServerState(player.getServer());
        state.markDirty();
        return playerState;
    }

    private static Type<DataManager> type = new Type<>(
            DataManager::new, // If there's no 'StateSaverAndLoader' yet create one
            DataManager::createFromNbt, // If there is a 'StateSaverAndLoader' NBT, parse it with 'createFromNbt'
            null // Supposed to be an 'DataFixTypes' enum, but we can just pass null
    );


    public static DataManager getServerState(MinecraftServer server) {
        PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager();
        DataManager state = persistentStateManager.getOrCreate(type, Rogue_block.MOD_ID);
        state.markDirty();
        return state;
    }
}
