package land.chipmunk.chipmunkmod.command;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.Text;
import net.minecraft.text.Texts;
import net.minecraft.text.MutableText;
import net.minecraft.util.Formatting;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.client.MinecraftClient;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import land.chipmunk.chipmunkmod.commands.*;

public class CommandManager {
  public CommandDispatcher<FabricClientCommandSource> dispatcher = new CommandDispatcher<>();
  public String prefix;

  public static CommandManager INSTANCE;

  public CommandManager (String prefix, CommandRegistryAccess commandRegistryAccess) {
    this.prefix = prefix;

    TestCommand.register(this.dispatcher);
    CoreCommand.register(this.dispatcher);
    UsernameCommand.register(this.dispatcher);
    CloopCommand.register(this.dispatcher);
    ValidateCommand.register(this.dispatcher);
    ItemCommand.register(this.dispatcher, commandRegistryAccess);
    CustomChatCommand.register(this.dispatcher);
    EvalCommand.register(this.dispatcher);
    MusicCommand.register(this.dispatcher);
    RainbowNameCommand.register(this.dispatcher);
    SayCommand.register(this.dispatcher);
    AutoSkinCommand.register(this.dispatcher);
    ReloadConfigCommand.register(this.dispatcher);
    SelfCareCommand.register(this.dispatcher);
  }

  public void executeCommand (String command) {
    final MinecraftClient client = MinecraftClient.getInstance();

    final FabricClientCommandSource commandSource = (FabricClientCommandSource) client.getNetworkHandler().getCommandSource();

    try {
      dispatcher.execute(command, commandSource);
    } catch (CommandSyntaxException e) {
      commandSource.sendError(Texts.toText(e.getRawMessage()));
      final Text context = getContext(e);
      if (context != null) commandSource.sendError(context);
    } catch (Exception e) {
      commandSource.sendError(Text.of(e.getMessage()));
    }
  }

  public Text getContext (CommandSyntaxException exception) {
    final int _cursor = exception.getCursor();
    final String input = exception.getInput();

    if (input == null || _cursor < 0) {
      return null;
    }
    final MutableText text = Text.literal("")
            .formatted(Formatting.GRAY);
    text.setStyle(text.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, prefix + input)));

    final int cursor = Math.min(input.length(), _cursor);

    if (cursor > CommandSyntaxException.CONTEXT_AMOUNT) {
      text.append(Text.literal("..."));
    }

    text
            .append(Text.literal(input.substring(Math.max(0, cursor - CommandSyntaxException.CONTEXT_AMOUNT), cursor)))
            .append(Text.literal(input.substring(cursor)).formatted(Formatting.RED, Formatting.UNDERLINE))
            .append(Text.translatable("command.context.here").formatted(Formatting.RED, Formatting.ITALIC));

    return text;
  }

  public static LiteralArgumentBuilder<FabricClientCommandSource> literal (String name) { return LiteralArgumentBuilder.literal(name); }
  public static <T> RequiredArgumentBuilder<FabricClientCommandSource, T> argument (String name, ArgumentType<T> type) { return RequiredArgumentBuilder.argument(name, type); }
}
