package me.km.snuviscript.commands;

import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.*;
import me.hammerle.snuviscript.code.ScriptManager;
import me.km.permissions.ModCommandManager;
import me.km.permissions.Permissions;
import me.km.snuviscript.Scripts;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.minecraft.command.arguments.*;
import net.minecraft.server.MinecraftServer;

public class CommandCommands {
    public static void registerFunctions(ScriptManager sm, Scripts scripts, Permissions perms,
            MinecraftServer server, ModCommandManager commands) {
        sm.registerConsumer("command.addignored", (sc, in) -> commands.addIgnoredCommands(in[0].getString(sc)));
        sm.registerConsumer("command.clearignored", (sc, in) -> commands.clearIgnoredCommands());
        sm.registerFunction("command.newhelp", (sc, in) -> {
            final String perm = in[1].getString(sc);
            return Commands.literal(in[0].getString(sc)).requires(p -> perms.has(p, perm));
        });
        sm.registerFunction("command.newhelpliteral", (sc, in) -> {
            LiteralArgumentBuilder<CommandSource> arg = Commands.literal(in[0].getString(sc));
            if(in.length >= 2) {
                final String perm = in[1].getString(sc);
                arg.requires(p -> perms.has(p, perm));
            }
            return arg;
        });
        sm.registerFunction("command.newhelpbool", (sc, in) -> {
            RequiredArgumentBuilder<CommandSource, Boolean> arg = Commands.argument(in[0].getString(sc), BoolArgumentType.bool());
            if(in.length >= 2) {
                final String perm = in[1].getString(sc);
                arg.requires(p -> perms.has(p, perm));
            }
            return arg;
        });
        sm.registerFunction("command.newhelpdouble", (sc, in) -> {
            double min = in[1].getDouble(sc);
            double max = in[2].getDouble(sc);
            RequiredArgumentBuilder<CommandSource, Double> arg = Commands.argument(in[0].getString(sc), DoubleArgumentType.doubleArg(min, max));
            if(in.length >= 4) {
                final String perm = in[3].getString(sc);
                arg.requires(p -> perms.has(p, perm));
            }
            return arg;
        });
        sm.registerFunction("command.newhelpfloat", (sc, in) -> {
            float min = in[1].getFloat(sc);
            float max = in[2].getFloat(sc);
            RequiredArgumentBuilder<CommandSource, Float> arg = Commands.argument(in[0].getString(sc), FloatArgumentType.floatArg(min, max));
            if(in.length >= 4) {
                final String perm = in[3].getString(sc);
                arg.requires(p -> perms.has(p, perm));
            }
            return arg;
        });
        sm.registerFunction("command.newhelpint", (sc, in) -> {
            int min = in[1].getInt(sc);
            int max = in[2].getInt(sc);
            RequiredArgumentBuilder<CommandSource, Integer> arg = Commands.argument(in[0].getString(sc), IntegerArgumentType.integer(min, max));
            if(in.length >= 4) {
                final String perm = in[3].getString(sc);
                arg.requires(p -> perms.has(p, perm));
            }
            return arg;
        });
        sm.registerFunction("command.newhelplong", (sc, in) -> {
            long min = in[1].getLong(sc);
            long max = in[2].getLong(sc);
            RequiredArgumentBuilder<CommandSource, Long> arg = Commands.argument(in[0].getString(sc), LongArgumentType.longArg(min, max));
            if(in.length >= 4) {
                final String perm = in[3].getString(sc);
                arg.requires(p -> perms.has(p, perm));
            }
            return arg;
        });
        sm.registerFunction("command.newhelpstring", (sc, in) -> {
            RequiredArgumentBuilder<CommandSource, String> arg;
            if(in[1].getBoolean(sc)) {
                arg = Commands.argument(in[0].getString(sc), StringArgumentType.greedyString());
            } else {
                arg = Commands.argument(in[0].getString(sc), StringArgumentType.string());
            }
            if(in.length >= 3) {
                final String perm = in[2].getString(sc);
                arg.requires(p -> perms.has(p, perm));
            }
            return arg;
        });
        sm.registerFunction("command.newhelpspecial", (sc, in) -> {
            RequiredArgumentBuilder<CommandSource, ArgumentType> arg = null;
            String name = in[0].getString(sc);
            switch(name) {
                case "Item":
                    arg = Commands.argument(in[1].getString(sc), (ArgumentType) ItemArgument.item());
                    break;
                case "Block":
                    arg = Commands.argument(in[1].getString(sc), (ArgumentType) BlockStateArgument.blockState());
                    break;
                case "Potion":
                    arg = Commands.argument(in[1].getString(sc), (ArgumentType) PotionArgument.mobEffect());
                    break;
                case "Enchantment":
                    arg = Commands.argument(in[1].getString(sc), (ArgumentType) EnchantmentArgument.enchantment());
                    break;
                case "Player":
                    arg = Commands.argument(in[1].getString(sc), (ArgumentType) EntityArgument.player());
                    break;
                default:
                    throw new IllegalArgumentException(String.format("'%s' is not a valid special help", name));
            }
            if(in.length >= 3) {
                final String perm = in[2].getString(sc);
                arg.requires(p -> perms.has(p, perm));
            }
            return arg;
        });
        sm.registerConsumer("command.sendhelp", (sc, in) -> {
            server.getPlayerList().getPlayers().forEach(p -> commands.send(p));
        });
        sm.registerConsumer("command.addhelpalias", (sc, in) -> {
            ((ArgumentBuilder) in[0].get(sc)).redirect(((ArgumentBuilder) in[1].get(sc)).build());
        });
        sm.registerConsumer("command.addhelpchild", (sc, in) -> {
            ((ArgumentBuilder) in[0].get(sc)).then(((ArgumentBuilder) in[1].get(sc)).build());
        });
        sm.registerConsumer("command.addhelp", (sc, in) -> {
            commands.addCustomNode(((LiteralArgumentBuilder<CommandSource>) in[0].get(sc)).build());
        });
        sm.registerConsumer("command.clearhelp", (sc, in) -> commands.clearCustomNodes());
        sm.registerConsumer("command.add", (sc, in) -> scripts.registerScriptCommand(in[0].getString(sc)));
        sm.registerConsumer("command.remove", (sc, in) -> scripts.unregisterScriptCommand(in[0].getString(sc)));
        sm.registerFunction("command.exists", (sc, in) -> scripts.isRegisteredScriptCommand(in[0].getString(sc)));
        sm.registerConsumer("command.clear", (sc, in) -> scripts.clearScriptCommands());
    }
}
