package dev.crucifixbeta.mod.modules;

import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.impl.ModuleToggleEvent;
import dev.crucifixbeta.core.impl.CommandManager;
import dev.crucifixbeta.mod.Mod;
import dev.crucifixbeta.mod.modules.impl.client.AntiCheat;
import dev.crucifixbeta.mod.modules.impl.client.BaritoneModule;
import dev.crucifixbeta.mod.modules.impl.client.ClickGui;
import dev.crucifixbeta.mod.modules.impl.client.ClientSetting;
import dev.crucifixbeta.mod.modules.impl.client.ColorsModule;
import dev.crucifixbeta.mod.modules.impl.client.hud.HudSetting;
import dev.crucifixbeta.mod.modules.settings.Setting;
import dev.crucifixbeta.mod.modules.settings.impl.BindSetting;
import dev.crucifixbeta.mod.modules.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.ColorSetting;
import dev.crucifixbeta.mod.modules.settings.impl.EnumSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import dev.crucifixbeta.mod.modules.settings.impl.StringSetting;
import java.util.ArrayList;
import java.util.List;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.PendingUpdateManager;
import net.minecraft.client.network.SequencedPacketCreator;
import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;

@Environment(EnvType.CLIENT)
public abstract class Module extends Mod {
   public final BooleanSetting drawn;
   public final BooleanSetting multiTask;
   public final SliderSetting combatPriority;
   private static Module usingItemPauseOwner;
   private static Module combatTaskOwner;
   private static long combatTaskUntil;
   private final List<Setting> settings = new ArrayList<>();
   private final String description;
   private final Module.Category category;
   private final BindSetting bindSetting;
   protected boolean state;
   private String chinese;

   public Module(String name, Module.Category category) {
      this(name, "", category);
   }

   public Module(String name, String description, Module.Category category) {
      super(name);
      this.category = category;
      this.description = description;
      this.bindSetting = this.add(new BindSetting("Key", this.isGuiModule() ? 344 : -1));
      this.drawn = this.add(new BooleanSetting("Drawn", !this.hideInModuleList()));
      this.multiTask = category == Module.Category.Combat ? this.add(new BooleanSetting("MultiTask", false)) : null;
      this.combatPriority = category == Module.Category.Combat ? this.add(new SliderSetting("TaskPriority", 10, 0, 100)) : null;
   }

   private boolean isGuiModule() {
      return this instanceof ClickGui;
   }

   private boolean hideInModuleList() {
      return this instanceof ColorsModule
         || this instanceof BaritoneModule
         || this instanceof AntiCheat
         || this instanceof ClientSetting
         || this instanceof HudSetting
         || this.getName().equals("Info");
   }

   public void setChinese(String chinese) {
      this.chinese = chinese;
   }

   public String getArrayName() {
      return this.getDisplayName() + this.getArrayInfo();
   }

   public String getArrayInfo() {
      return this.getInfo() == null ? "" : " §7[§f" + this.getInfo() + "§7]";
   }

   public String getInfo() {
      return null;
   }

   public String getDisplayName() {
      return ClientSetting.INSTANCE != null && ClientSetting.INSTANCE.chinese.getValue() && this.chinese != null ? this.chinese : this.getName();
   }

   public String getChineseName() {
      return this.chinese;
   }

   public String getDescription() {
      return this.description;
   }

   public Module.Category getCategory() {
      return this.category;
   }

   public BindSetting getBindSetting() {
      return this.bindSetting;
   }

   public boolean isMultiTaskEnabled() {
      return this.multiTask != null && this.multiTask.getValue();
   }

   public boolean shouldPauseForUsingItem() {
      return mc.player != null && (mc.player.isUsingItem() && !this.isMultiTaskEnabled() || this.isPausedByUsingItemOwner() || this.shouldPauseForCombatTask());
   }

   public float getCombatPriority() {
      return this.combatPriority == null ? 10.0F : this.combatPriority.getValueFloat();
   }

   public boolean isOn() {
      return this.state;
   }

   public boolean isOff() {
      return !this.isOn();
   }

   public void toggle() {
      if (this.isOn()) {
         this.disable();
      } else {
         this.enable();
      }
   }

   public void enable() {
      if (!this.state) {
         ClientSetting var1 = ClientSetting.INSTANCE;
         boolean var2 = !nullCheck() && this.drawn.getValue() && var1 != null && var1.toggle.getValue();
         if (var2) {
            int var3 = var1.onlyOne.getValue() ? -1 : System.identityHashCode(this);
            switch ((ClientSetting.Style)var1.messageStyle.getValue()) {
               case Mio:
                  CommandManager.sendMessageId("§2[+] §f" + this.getDisplayName(), var3);
                  break;
               case Debug:
                  CommandManager.sendMessageId(this.getCategory().name().toLowerCase() + "." + this.getDisplayName().toLowerCase() + ".§aenable", var3);
                  break;
               case Lowercase:
                  CommandManager.sendMessageId(this.getDisplayName().toLowerCase() + " §aenabled", var3);
                  break;
               case Melon:
                  CommandManager.sendMessageId("§b" + this.getDisplayName() + " §aEnabled.", var3);
                  break;
               case Normal:
                  CommandManager.sendMessageId("§f" + this.getDisplayName() + " §aEnabled", var3);
                  break;
               case Future:
                  CommandManager.sendMessageId("§7" + this.getDisplayName() + " toggled §aon", var3);
                  break;
               case Chinese:
                  CommandManager.sendMessageId(this.getDisplayName() + " §a开启", var3);
                  break;
               case Moon:
                  CommandManager.sendChatMessageWidthIdNoSync(
                     "§f[§b" + var1.hackName.getValue() + "§f] [§3" + this.getDisplayName() + "§f] §7toggled §aon", var3
                  );
                  break;
               case Earth:
                  CommandManager.sendChatMessageWidthIdNoSync("§l" + this.getDisplayName() + " §aenabled.", var3);
            }
         }

         if (CrucifixBeta.MODULE != null) {
            CrucifixBeta.MODULE.showToggleBanner(this, true);
         }

         this.state = true;
         CrucifixBeta.EVENT_BUS.subscribe(this);
         CrucifixBeta.EVENT_BUS.post(new ModuleToggleEvent(this, true));
         this.onToggle();
         this.onEnable();
      }
   }

   public void disable() {
      if (this.state) {
         this.releaseUsingItemPause();
         this.releaseCombatTask();
         ClientSetting var1 = ClientSetting.INSTANCE;
         boolean var2 = !nullCheck() && this.drawn.getValue() && var1 != null && var1.toggle.getValue();
         if (var2) {
            int var3 = var1.onlyOne.getValue() ? -1 : System.identityHashCode(this);
            switch ((ClientSetting.Style)var1.messageStyle.getValue()) {
               case Mio:
                  CommandManager.sendMessageId("§4[-] §f" + this.getDisplayName(), var3);
                  break;
               case Debug:
                  CommandManager.sendMessageId(this.getCategory().name().toLowerCase() + "." + this.getDisplayName().toLowerCase() + ".§cdisable", var3);
                  break;
               case Lowercase:
                  CommandManager.sendMessageId(this.getDisplayName().toLowerCase() + " §cdisabled", var3);
                  break;
               case Melon:
                  CommandManager.sendMessageId("§b" + this.getDisplayName() + " §cDisabled.", var3);
                  break;
               case Normal:
                  CommandManager.sendMessageId("§f" + this.getDisplayName() + " §cDisabled", var3);
                  break;
               case Future:
                  CommandManager.sendMessageId("§7" + this.getDisplayName() + " toggled §coff", var3);
                  break;
               case Chinese:
                  CommandManager.sendMessageId(this.getDisplayName() + " §c关闭", var3);
                  break;
               case Moon:
                  CommandManager.sendChatMessageWidthIdNoSync(
                     "§f[§b" + var1.hackName.getValue() + "§f] [§3" + this.getDisplayName() + "§f] §7toggled §coff", var3
                  );
                  break;
               case Earth:
                  CommandManager.sendChatMessageWidthIdNoSync("§l" + this.getDisplayName() + " §cdisabled.", var3);
            }
         }

         if (CrucifixBeta.MODULE != null) {
            CrucifixBeta.MODULE.showToggleBanner(this, false);
         }

         this.state = false;
         CrucifixBeta.EVENT_BUS.post(new ModuleToggleEvent(this, false));
         CrucifixBeta.EVENT_BUS.unsubscribe(this);
         this.onToggle();
         this.onDisable();
      }
   }

   public void sendMessage(String message) {
      CommandManager.sendMessage(message);
   }

   public void setState(boolean state) {
      if (this.state != state) {
         if (state) {
            this.enable();
         } else {
            this.disable();
         }
      }
   }

   public boolean setBind(String rkey) {
      if (rkey.equalsIgnoreCase("none")) {
         this.bindSetting.setValue(-1);
         return true;
      } else {
         try {
            int var2 = InputUtil.fromTranslationKey("key.keyboard." + rkey.toLowerCase()).getCode();
            if (var2 == 0) {
               return false;
            } else {
               this.bindSetting.setValue(var2);
               return true;
            }
         } catch (NumberFormatException var3) {
            if (!nullCheck()) {
               this.sendMessage("\u00a74Bad bind!");
            }

            return false;
         }
      }
   }

   public void onDisable() {
   }

   public void onEnable() {
   }

   public void onToggle() {
   }

   public void onUpdate() {
   }

   public void onLogin() {
   }

   public void onLogout() {
   }

   public void onRender2D(DrawContext drawContext, float tickDelta) {
   }

   public void onRender3D(MatrixStack matrixStack) {
   }

   protected void holdUsingItemPause() {
      if (!this.isMultiTaskEnabled()) {
         usingItemPauseOwner = this;
      }
   }

   protected void releaseUsingItemPause() {
      if (usingItemPauseOwner == this) {
         usingItemPauseOwner = null;
      }
   }

   protected boolean isPausedByUsingItemOwner() {
      return usingItemPauseOwner != null && usingItemPauseOwner != this;
   }

   protected boolean shouldPauseForCombatTask() {
      if (!this.usesCombatTaskLock()) {
         return false;
      } else {
         clearExpiredCombatTask();
         return combatTaskOwner != null && combatTaskOwner != this;
      }
   }

   protected boolean tryUseCombatTask() {
      return this.tryUseCombatTask(250L);
   }

   protected boolean tryUseCombatTask(long holdMs) {
      if (!this.usesCombatTaskLock()) {
         return true;
      } else {
         clearExpiredCombatTask();
         if (combatTaskOwner != null && combatTaskOwner != this && this.getCombatPriority() <= combatTaskOwner.getCombatPriority()) {
            return false;
         } else {
            combatTaskOwner = this;
            combatTaskUntil = System.currentTimeMillis() + Math.max(50L, holdMs);
            return true;
         }
      }
   }

   protected void releaseCombatTask() {
      if (combatTaskOwner == this) {
         combatTaskOwner = null;
         combatTaskUntil = 0L;
      }
   }

   private boolean usesCombatTaskLock() {
      return this.category == Module.Category.Combat && !this.isMultiTaskEnabled();
   }

   private static void clearExpiredCombatTask() {
      if (combatTaskOwner != null) {
         if (combatTaskOwner.isOff() || combatTaskOwner.isMultiTaskEnabled() || System.currentTimeMillis() > combatTaskUntil) {
            combatTaskOwner = null;
            combatTaskUntil = 0L;
         }
      }
   }

   public void addSetting(Setting setting) {
      this.settings.add(setting);
   }

   public StringSetting add(StringSetting setting) {
      this.addSetting(setting);
      return setting;
   }

   public ColorSetting add(ColorSetting setting) {
      this.addSetting(setting);
      return setting;
   }

   public SliderSetting add(SliderSetting setting) {
      this.addSetting(setting);
      return setting;
   }

   public BooleanSetting add(BooleanSetting setting) {
      this.addSetting(setting);
      return setting;
   }

   public <T extends Enum<T>> EnumSetting<T> add(EnumSetting<T> setting) {
      this.addSetting(setting);
      return setting;
   }

   public BindSetting add(BindSetting setting) {
      this.addSetting(setting);
      return setting;
   }

   public List<Setting> getSettings() {
      return this.settings;
   }

   public static boolean nullCheck() {
      return mc.player == null || mc.player.input == null || mc.world == null;
   }

   public static void sendSequencedPacket(SequencedPacketCreator packetCreator) {
      if (mc.getNetworkHandler() != null && mc.world != null) {
         try (PendingUpdateManager var1 = mc.world.getPendingUpdateManager().incrementSequence()) {
            mc.getNetworkHandler().sendPacket(packetCreator.predict(var1.getSequence()));
         }
      }
   }
   @Environment(EnvType.CLIENT)
   public enum Category {
      Combat("b", "战斗"),
      Misc("[", "杂项"),
      Render("a", "渲染"),
      Movement("8", "移动"),
      Player("5", "玩家"),
      Exploit("6", "利用"),
      Client("7", "客户端"),
      Debug("?", "调试"),
      HUD("4", "HUD");

      private final String icon;
      private final String chineseName;

      Category(String icon, String chineseName) {
         this.icon = icon;
         this.chineseName = chineseName;
      }

      public String getIcon() {
         return this.icon;
      }

      public String getDisplayName() {
         return ClientSetting.INSTANCE != null && ClientSetting.INSTANCE.chinese.getValue()
            ? this.chineseName
            : this.name();
      }
   }
}
