/*
 *
 * ShortcutCommands
 *
 * A class that simplifies some of the current vanilla commands with shortcut commands in the game. You may remember an old plugin
 * called "Essentials" (Or EssentialsEx in a later version) -> This file is re-creating a portion of that plugin but in mod-format
 *
 *
*/

package jesse.keeblarcraft.Commands;

import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.context.CommandContext;

import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.Utils.PlayerChecks;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.command.TimeCommand;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;

public class ShortcutCommands {
    float SPEED_SCALAR = 20.0f; // For clamping speed down to half of its max output (So 0.5 will be max speed on a system that goes up in 0.05'ths)

    public void RegisterShortcutCommands()
    {
        // Abstract handling "value" to parse gamemodes 0-2 (survival; creative; spectator)
        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            dispatcher.register(CommandManager.literal("gm")
            .then(CommandManager.argument("value", IntegerArgumentType.integer())
            .executes(context -> GamemodeShortcut(IntegerArgumentType.getInteger(context, "value"), context))));
        });

        // Fly command
        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            var flightNode = CommandManager.literal("fly").executes(context -> FlightSpeedShortcut(null, context)).build();

            var flightSpeed = CommandManager.argument("value", IntegerArgumentType.integer())
            .executes(context -> FlightSpeedShortcut(IntegerArgumentType.getInteger(context, "value"), context)).build();

            dispatcher.getRoot().addChild(flightNode);
            flightNode.addChild(flightSpeed);
        });

        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            var healNode = CommandManager.literal("heal").executes(context -> HealShortcut(context, null)).build();
            var targetPlayer = CommandManager.argument("targetPlayer", EntityArgumentType.player())
            .executes(context -> HealShortcut(context, EntityArgumentType.getPlayer(context, "targetPlayer"))).build();

            dispatcher.getRoot().addChild(healNode);
            healNode.addChild(targetPlayer);
        });

        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            var feedNode = CommandManager.literal("feed").executes(context -> FeedShortcut(context, null)).build();
            var targetPlayer = CommandManager.argument("targetPlayer", EntityArgumentType.player())
            .executes(context -> FeedShortcut(context, EntityArgumentType.getPlayer(context, "targetPlayer"))).build();

            dispatcher.getRoot().addChild(feedNode);
            feedNode.addChild(targetPlayer);
        });

        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            dispatcher.register(CommandManager.literal("day")
            .executes(context -> { DayShortcut(context);
                return 0;
            }));
        });

        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            dispatcher.register(CommandManager.literal("night")
            .executes(context -> { NightShortcut(context);
                return 0;
            }));
        });
    }

    /// Command handlers below
    private int GamemodeShortcut(int value, CommandContext<ServerCommandSource> context)
    {
        int retValue = -1;
        if (context.getSource().isExecutedByPlayer()) {
            ServerPlayerEntity player = context.getSource().getPlayer();

            /// todo: change 4 to be OPERATOR level. 4 is DEFAULT operator level in Minecraft
            if(player.hasPermissionLevel(4)) {
                switch(value) {
                    case 0:
                        player.changeGameMode(net.minecraft.world.GameMode.SURVIVAL);
                        player.sendMessage(Text.literal("Changing your game mode to SURVIVAL"));
                        retValue = 0;
                        break;
                    case 1:
                        player.changeGameMode(net.minecraft.world.GameMode.CREATIVE);
                        player.sendMessage(Text.literal("Changing your game mode to CREATIVE"));
                        retValue = 0;
                        break;
                    case 2:
                        player.changeGameMode(net.minecraft.world.GameMode.SPECTATOR);
                        player.sendMessage(Text.literal("Changing your game mode to SPECTATOR"));
                        retValue = 0;
                        break;
                    default:
                        player.sendMessage(Text.literal("Valid entries are 0=SURVIVAL, 1=CREATIVE, 2=SPECTATOR"));
                        retValue = -1;
                    break;
                }
            }
            else {
                player.sendMessage(Text.literal("\033[31m You do not have permissions to run this command! \033[0m"));
            }
        }
        else {
            Keeblarcraft.LOGGER.info("This command cannot be executed by a non-player entity!");
        }
        return retValue;
    }

    private int FlightSpeedShortcut(Integer value, CommandContext<ServerCommandSource> context) {
        if (PlayerChecks.HasPermission(context)) {
            ServerPlayerEntity player = context.getSource().getPlayer();
            PlayerAbilities abilities = player.getAbilities();

            // Disable flight
            if (abilities.flying && value == null) {
                abilities.flying = false;
                abilities.allowFlying = false;
                abilities.setFlySpeed(0);
                player.sendMessage(Text.of("Disabled flight"));
                player.sendAbilitiesUpdate();
            } else if (!abilities.flying && value == null) {
                value = 1;
            }

            // Enable flight
            if (value != null && value >= 1 && value <= 10) {
                abilities.allowFlying = true;
                abilities.setFlySpeed((float) (value / SPEED_SCALAR)); // Dividing by 20f yields max clamp value of 0.5 since MC does 0.0-> 1.0 flight. 0.1 flight is too fast!
                player.sendAbilitiesUpdate();
                player.sendMessage(Text.of("Flight speed set to " + value));
            } else if (value != null) {
                player.sendMessage(Text.literal("Only values from 1-10 are accepted"));
            }
        }

        return 0;
    }

    private int FeedShortcut(CommandContext<ServerCommandSource> context, ServerPlayerEntity target) {
        if (PlayerChecks.HasPermission(context)) {
            // if target is null, feed ourselves
            if (target == null) {
                ServerPlayerEntity player = context.getSource().getPlayer();
                player.getHungerManager().setExhaustion(0.0f);
                player.getHungerManager().setFoodLevel(20); // 20 is hardcoded inside class
                player.getHungerManager().setSaturationLevel(10.0f); // 5 is set in constructor, but let's try 10!
                player.sendMessage(Text.of("You were just super fed!"));
            } else {
                target.getHungerManager().setExhaustion(0.0f);
                target.getHungerManager().setFoodLevel(20); // 20 is hardcoded inside class
                target.getHungerManager().setSaturationLevel(10.0f); // 5 is set in constructor, but let's try 10!
                target.sendMessage(Text.of("You were just super fed!"));
            }
        }
        return 0;
    }

    private int HealShortcut(CommandContext<ServerCommandSource> context, ServerPlayerEntity target) {
        int retValue = -1;
        if (PlayerChecks.HasPermission(context)) {
            // If no player specified; then heal ourself full HP
            if (target == null) {
                context.getSource().getPlayer().setHealth(context.getSource().getPlayer().getMaxHealth());
                context.getSource().getPlayer().sendMessage(Text.of("Healed!"));
            } else {
                target.setHealth(target.getMaxHealth());
                target.sendMessage(Text.of("You were just healed!"));
                context.getSource().getPlayer().sendMessage(Text.of("You healed " + target.getEntityName()));
            }
        }
        return retValue;
    }

    private int DayShortcut(CommandContext<ServerCommandSource> context) {
        int retValue = -1;
        if (context.getSource().isExecutedByPlayer()) {
            ServerPlayerEntity player = context.getSource().getPlayer();

            if (player.hasPermissionLevel(4)) {
                retValue=0;
                TimeCommand.executeSet(context.getSource(), retValue);
            } else {
                player.sendMessage(Text.literal("You do not have permission for this command"));
            }
        }

        return retValue;
    }
    private int NightShortcut(CommandContext<ServerCommandSource> context) {
        int retValue = -1;
        if (context.getSource().isExecutedByPlayer()) {
            ServerPlayerEntity player = context.getSource().getPlayer();

            if (player.hasPermissionLevel(4)) {
                retValue=13000;
                TimeCommand.executeSet(context.getSource(), retValue);
            } else {
                player.sendMessage(Text.literal("You do not have permission for this command"));
            }
        }

        return retValue;
    }
}
