package me.km.snuviscript.commands;

import java.util.ArrayList;
import java.util.stream.Collectors;
import me.hammerle.snuviscript.code.ScriptManager;
import me.km.utils.Location;
import me.km.utils.Mapper;
import me.km.utils.ReflectionUtils;
import me.km.world.WorldManager;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.Difficulty;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.WorldInfo;

public class WorldCommands {
    @SuppressWarnings("")
    public static void registerFunctions(ScriptManager sm, MinecraftServer server) {
        sm.registerAlias("players.toworldlist", "world.getplayers");
        sm.registerFunction("world.register", (sc, in) -> WorldManager.register(in[0].getString(sc)));
        sm.registerFunction("world.unregister", (sc, in) -> WorldManager.unregister(server, in[0].getString(sc)));
        sm.registerFunction("world.get", (sc, in) -> WorldManager.get(server, in[0].getString(sc)));
        sm.registerFunction("world.getname", (sc, in) -> WorldManager.getName((World) in[0].get(sc)));
        sm.registerConsumer("world.setdiffi", (sc, in) -> {
            Difficulty diffi = Difficulty.valueOf(in[1].getString(sc).toUpperCase());
            ((World) in[0].get(sc)).getWorldInfo().setDifficulty(diffi);
        });
        sm.registerConsumer("world.setgamerule", (sc, in) -> {
            Object o = ((World) in[0].get(sc)).getGameRules().get(Mapper.getGameRule(in[1].getString(sc)));
            if(o instanceof GameRules.BooleanValue) {
                ((GameRules.BooleanValue) o).set(in[2].getBoolean(sc), server);
            } else if(o instanceof GameRules.IntegerValue) {
                ReflectionUtils.setIntegerValue((GameRules.IntegerValue) o, in[2].getInt(sc));
            }
        });
        sm.registerFunction("world.getgamerule", (sc, in) -> {
            Object o = ((World) in[0].get(sc)).getGameRules().get(Mapper.getGameRule(in[1].getString(sc)));
            if(o instanceof GameRules.BooleanValue) {
                return ((GameRules.BooleanValue) o).get();
            } else if(o instanceof GameRules.IntegerValue) {
                return (double) ((GameRules.IntegerValue) o).get();
            }
            return null;
        });
        sm.registerConsumer("world.setspawn", (sc, in) -> {
            Location l = ((Location) in[0].get(sc));
            l.getWorld().getWorldInfo().setSpawn(l.getBlockPos());
        });
        sm.registerFunction("world.getspawn", (sc, in) -> {
            World w = (World) in[0].get(sc);
            WorldInfo info = w.getWorldInfo();
            return new Location(w, info.getSpawnX(), info.getSpawnY(), info.getSpawnZ(), 0.0f, 0.0f);
        });
        sm.registerFunction("world.getall", (sc, in) -> {
            ArrayList<World> worlds = new ArrayList<>();
            for(World w : server.getWorlds()) {
                worlds.add(w);
            }
            return worlds;
        });
        sm.registerConsumer("world.settime", (sc, in) -> ((World) in[0].get(sc)).setDayTime(in[1].getLong(sc)));
        sm.registerFunction("world.gettime", (sc, in) -> (double) ((World) in[0].get(sc)).getDayTime());
        sm.registerFunction("world.hasstorm", (sc, in) -> ((World) in[0].get(sc)).isRaining());
        sm.registerConsumer("world.clearweather", (sc, in) -> {
            WorldInfo wi = ((World) in[0].get(sc)).getWorldInfo();
            wi.setClearWeatherTime(in[1].getInt(sc));
            wi.setRainTime(0);
            wi.setThunderTime(0);
            wi.setRaining(false);
            wi.setThundering(false);
        });
        sm.registerConsumer("world.setrain", (sc, in) -> {
            WorldInfo wi = ((World) in[0].get(sc)).getWorldInfo();
            wi.setClearWeatherTime(0);
            int i = in[1].getInt(sc);
            wi.setRainTime(i);
            wi.setThunderTime(i);
            wi.setRaining(true);
            wi.setThundering(false);
        });
        sm.registerConsumer("world.setthunder", (sc, in) -> {
            WorldInfo wi = ((World) in[0].get(sc)).getWorldInfo();
            wi.setClearWeatherTime(0);
            int i = in[1].getInt(sc);
            wi.setRainTime(i);
            wi.setThunderTime(i);
            wi.setRaining(true);
            wi.setThundering(true);
        });
        sm.registerFunction("world.getentities", (sc, in) -> {
            return ((ServerWorld) in[0].get(sc)).getEntities().collect(Collectors.toList());
        });
    }
}
