package jesse.keeblarcraft.Commands;

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

import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.JsonClassObjects.PlayerNote;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;

public class NoteCommands {
    /// Class Variables
    ConfigManager notesConfig = new ConfigManager();
    String NOTES_GLOBAL_DIRECTORY = "notes"; // The overall "notes" dir inside cfg folder

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         NoteCommands
    /////////////////////////////////////////////////////////////////////////////
    public NoteCommands() {}

    //TODO: Rework note commands upon story mode release
    /////////////////////////////////////////////////////////////////////////////
    /// @fn         RegisterNoteCommands
    ///
    /// @brief      Registers all the commands for this class
    /////////////////////////////////////////////////////////////////////////////
    public void RegisterNoteCommands() {
        // Command: "/addnote note goes here"
        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            dispatcher.register(CommandManager.literal("addnote")
            .then(CommandManager.argument("value", StringArgumentType.greedyString())
            .executes(context -> AddNote(StringArgumentType.getString(context, "value"), context))));
        });

        // Command: "/delnote noteIdHere"
        // CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
        //     dispatcher.register(CommandManager.literal("delnote")
        //     .then(CommandManager.argument("value", StringArgumentType.greedyString())
        //     .executes(context -> AddNote(StringArgumentType.getString(context, "value"), context))));
        // });

        // Command: "/purgenotes"
        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            dispatcher.register(CommandManager.literal("purgenotes")
            .executes(context -> PurgeAllNotes(context)));
        });

        // Command: "/modifynote noteIdHere new_note_string_here"
        // Alises: "/editnote"
        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            final var mNote = dispatcher.register(CommandManager.literal("editnote")
            .then(CommandManager.argument("note_id", IntegerArgumentType.integer())
            .then(CommandManager.argument("new_note", StringArgumentType.string())
            .executes(context -> ModifyNote(
                IntegerArgumentType.getInteger(context, "note_id"),
                StringArgumentType.getString(context, "new_note"),
                context)))));

                dispatcher.register(CommandManager.literal("editnote").redirect(mNote));
        });

        // Command Root: "/delnote noteIdHere"
        // Aliases: "/rmnote", "/deletenote"
        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            final var rootDeleteCmd = dispatcher.register(CommandManager.literal("delnote")
            .then(CommandManager.argument("value", IntegerArgumentType.integer())
            .executes(context -> DeleteNote(IntegerArgumentType.getInteger(context, "value"), context))));

            // Alias redirects
            dispatcher.register(CommandManager.literal("rmnote").redirect(rootDeleteCmd));
            dispatcher.register(CommandManager.literal("deletenote").redirect(rootDeleteCmd));
        });

        // Command Root: "/notegui"
        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            dispatcher.register(CommandManager.literal("notegui")
            .executes(context -> { OpenNoteGui(context);
                return 0;
            }));
        });

        // Command Root: "/notelist"
        // Aliases: "/listnotes"
        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            final var rootListNotes = dispatcher.register(CommandManager.literal("notelist")
            .executes(context -> { ListNotes(context);
                return 0;
            }));

            dispatcher.register(CommandManager.literal("listnotes").redirect(rootListNotes));
        });
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         AddNote
    ///
    /// @brief      Adds a new note to the players notebook
    ///
    /// @arg[in]    value is the new note to be added
    ///
    /// @arg[in]    context is the context of the ServerCommandSource object
    ///             the command was run with
    ///
    /// @return     0 if success, -1 if not
    /////////////////////////////////////////////////////////////////////////////
    private Integer AddNote(String value, CommandContext<ServerCommandSource> context) {
        Integer ret = -1;

        if (context.getSource().isExecutedByPlayer()) {
            ServerPlayerEntity player = context.getSource().getPlayer();

            // Note mgmt
            PlayerNote note = new PlayerNote(player.getUuidAsString());
            note.AddNote(value, 1, 1, 1, 1);
            player.sendMessage(Text.of("New note logged to entry! View notes any time with /notegui"));

            ret = 0;
        } else {
            System.out.println("Only a player can execute this command!");
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         DeleteNote
    ///
    /// @brief      Deletes a note by id
    ///
    /// @arg[in]    value is the integer ID of the note to be deleted
    ///
    /// @arg[in]    context is the context of the ServerCommandSource object
    ///             the command was run with
    ///
    /// @return     0 if success, -1 if not
    /////////////////////////////////////////////////////////////////////////////
    private int DeleteNote(int value, CommandContext<ServerCommandSource> context) {
        int ret = -1;

        if (context.getSource().isExecutedByPlayer()) {
            ServerPlayerEntity player = context.getSource().getPlayer();

            PlayerNote note = new PlayerNote(player.getUuidAsString());
            player.sendMessage(Text.of("Deleted note entry. View notes any time with /notegui"));

            ret = 0;
            note.DeleteNote(value);
        } else {
            System.out.println("Only a player can execute this command!");
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         ModifyNote
    ///
    /// @brief      Modifies a single note by id value
    ///
    /// @arg[in]    value is the integer ID of the note to be modified
    ///
    /// @arg[in]    newNote is the new version of the edited note
    ///
    /// @arg[in]    context is the context of the ServerCommandSource object
    ///             the command was run with
    ///
    /// @return     0 if success, -1 if not
    /////////////////////////////////////////////////////////////////////////////
    private int ModifyNote(Integer value, String newNote, CommandContext<ServerCommandSource> context) {
        int ret = -1;

        if (context.getSource().isExecutedByPlayer() && value > 0) {
            ServerPlayerEntity player = context.getSource().getPlayer();
            PlayerNote note = new PlayerNote(player.getUuidAsString());

            long time = context.getSource().getWorld().getTime();
            // long day = ; ///TODO: Docs lack this for some reason? Add in future
            long epochTime = System.currentTimeMillis();
            long storyChapter = -1; // Intentional garbage until story is fleshed out later (TODO)
            long storyPart = -1; // Intentional garbage until story is fleshed out later (TODO)

            note.ModifyNote(value, newNote, epochTime, storyChapter, storyPart);

            player.sendMessage(Text.of("Modified note entry. View notes any time with /notegui"));


            ret = 0;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         PurgeAllNotes
    ///
    /// @brief      Removes all notes from a players note file
    ///
    /// @arg[in]    context is the context of the ServerCommandSource object
    ///             the command was run with
    ///
    /// @return     0 if success, -1 if not
    /////////////////////////////////////////////////////////////////////////////
    private int PurgeAllNotes(CommandContext<ServerCommandSource> context) {
        int ret = -1;

        if (context.getSource().isExecutedByPlayer()) {
            ServerPlayerEntity player = context.getSource().getPlayer();

            PlayerNote note = new PlayerNote(player.getUuidAsString());
            note.PurgeAllNotes();
            player.sendMessage(Text.of("Purged all notes. View notes any time with /notegui"));

            ret = 0;
        } else {
            System.out.println("Only a player can execute this command!");
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         ListNotes
    ///
    /// @brief      Lists notes in pages in the players active chat
    ///
    /// @arg[in]    context is the context of the ServerCommandSource object
    ///             the command was run with
    ///
    /// @return     0 if success, -1 if not
    /////////////////////////////////////////////////////////////////////////////
    private int ListNotes(CommandContext<ServerCommandSource> context) {
        int ret = -1;

        if (context.getSource().isExecutedByPlayer()) {
            ServerPlayerEntity player = context.getSource().getPlayer();

            PlayerNote notes = new PlayerNote(player.getUuidAsString());
            for (int i = 0; i <= notes.GetNotebookSize(); i++) {
                String individualNote = notes.GetNoteString(i);
                if (individualNote != "") {
                    player.sendMessage(Text.of("Note " + i + ": " + individualNote));
                }
            }

            ret = 0;
        } else {
            System.out.println("Only a player can execute this command!");
        }

        return ret;
    }

    ///TODO: Blocked until GUI manager is available
    /////////////////////////////////////////////////////////////////////////////
    /// @fn         OpenNoteGui
    ///
    /// @brief      Opens up the graphical display of the note manager
    ///
    /// @arg[in]    context is the context of the ServerCommandSource object
    ///             the command was run with
    ///
    /// @return     0 if success, -1 if not
    /////////////////////////////////////////////////////////////////////////////
    private int OpenNoteGui(CommandContext<ServerCommandSource> context) {
        int ret = -1;

        if (context.getSource().isExecutedByPlayer()) {
            ServerPlayerEntity player = context.getSource().getPlayer();

            ret = 0;
        } else {
            System.out.println("Only a player can execute this command!");
        }

        return ret;
    }
}
