package dev.crucifixbeta.mod.modules.impl.client.hud;

import asm.accessors.ISimpleRegistry;
import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.ClientTickEvent;
import dev.crucifixbeta.api.utils.math.Animation;
import dev.crucifixbeta.api.utils.math.Easing;
import dev.crucifixbeta.api.utils.render.ColorUtil;
import dev.crucifixbeta.api.utils.render.Render2DUtil;
import dev.crucifixbeta.api.utils.render.TextUtil;
import dev.crucifixbeta.core.impl.FontManager;
import dev.crucifixbeta.mod.modules.HudModule;
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.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.EnumSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import java.awt.Color;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.function.BooleanSupplier;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.registry.Registries;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.world.World;

@Environment(EnvType.CLIENT)
public class InfoHudModule extends HudModule {
   public static InfoHudModule INSTANCE;
   public final EnumSetting<InfoHudModule.Page> page = this.add(new EnumSetting<>("Page", InfoHudModule.Page.General));
   public final BooleanSetting renderingUp = this.add(new BooleanSetting("RenderingUp", false, () -> this.page.is(InfoHudModule.Page.General)));
   public final BooleanSetting lowerCase = this.add(new BooleanSetting("LowerCase", false, () -> this.page.is(InfoHudModule.Page.General)));
   public final BooleanSetting sort = this.add(new BooleanSetting("Sort", false, () -> this.page.is(InfoHudModule.Page.General)));
   public final BooleanSetting rightAlign = this.add(new BooleanSetting("RightAlign", true, () -> this.page.is(InfoHudModule.Page.General)));
   public final SliderSetting xOffset = this.add(
      new SliderSetting("XOffset", 0.0, 0.0, 50.0, 0.1, () -> this.page.is(InfoHudModule.Page.General))
   );
   public final SliderSetting yOffset = this.add(
      new SliderSetting("YOffset", 0.0, 0.0, 50.0, 0.1, () -> this.page.is(InfoHudModule.Page.General))
   );
   public final SliderSetting textOffset = this.add(
      new SliderSetting("TextOffset", 0.0, -10.0, 10.0, 0.1, () -> this.page.is(InfoHudModule.Page.General))
   );
   public final SliderSetting interval = this.add(
      new SliderSetting("Interval", 0.0, 0.0, 15.0, 0.1, () -> this.page.is(InfoHudModule.Page.General))
   );
   public final SliderSetting enableLength = this.add(
      new SliderSetting("EnableLength", 200, 0, 1000, () -> this.page.is(InfoHudModule.Page.General))
   );
   public final SliderSetting disableLength = this.add(
      new SliderSetting("DisableLength", 200, 0, 1000, () -> this.page.is(InfoHudModule.Page.General))
   );
   public final SliderSetting fadeLength = this.add(
      new SliderSetting("FadeLength", 200, 0, 1000, () -> this.page.is(InfoHudModule.Page.General))
   );
   public final EnumSetting<Easing> easing = this.add(
      new EnumSetting<>("Easing", Easing.CircInOut, () -> this.page.is(InfoHudModule.Page.General))
   );
   public final BooleanSetting fps = this.add(new BooleanSetting("FPS", true, () -> this.page.is(InfoHudModule.Page.Element)));
   public final BooleanSetting ping = this.add(new BooleanSetting("Ping", true, () -> this.page.is(InfoHudModule.Page.Element)));
   public final BooleanSetting tps = this.add(new BooleanSetting("TPS", true, () -> this.page.is(InfoHudModule.Page.Element)));
   public final BooleanSetting ip = this.add(new BooleanSetting("IP", false, () -> this.page.is(InfoHudModule.Page.Element)));
   public final BooleanSetting time = this.add(new BooleanSetting("Time", false, () -> this.page.is(InfoHudModule.Page.Element)));
   public final BooleanSetting speed = this.add(new BooleanSetting("Speed", true, () -> this.page.is(InfoHudModule.Page.Element)));
   public final BooleanSetting coords = this.add(new BooleanSetting("Coords", true, () -> this.page.is(InfoHudModule.Page.Element)));
   public final BooleanSetting brand = this.add(new BooleanSetting("Brand", false, () -> this.page.is(InfoHudModule.Page.Element)));
   public final BooleanSetting potions = this.add(new BooleanSetting("Potions", true, () -> this.page.is(InfoHudModule.Page.Element)));
   public final BooleanSetting blur = this.add(new BooleanSetting("Blur", false, () -> this.page.is(InfoHudModule.Page.Color)).setParent());
   public final SliderSetting radius = this.add(
      new SliderSetting("Radius", 10.0, 0.0, 100.0, () -> this.page.is(InfoHudModule.Page.Color) && this.blur.isOpen())
   );
   private final BooleanSetting backGround = this.add(
      new BooleanSetting("BackGround", false, () -> this.page.is(InfoHudModule.Page.Color)).setParent()
   );
   public final SliderSetting width = this.add(
      new SliderSetting("Width", 0.0, 0.0, 15.0, () -> this.page.is(InfoHudModule.Page.Color) && this.backGround.isOpen())
   );
   private final BooleanSetting rect = this.add(new BooleanSetting("Rect", false, () -> this.page.is(InfoHudModule.Page.Color)));
   private final BooleanSetting glow = this.add(new BooleanSetting("Glow", false, () -> this.page.is(InfoHudModule.Page.Color)));
   private final DecimalFormat decimal = new DecimalFormat("0.0");
   private final ArrayList<InfoHudModule.Info> infoList = new ArrayList<>();

   public InfoHudModule() {
      super("Info", "", "Info", 2, 2, HudModule.Corner.RightBottom);
      INSTANCE = this;

      for (StatusEffect var2 : Registries.STATUS_EFFECT) {
         try {
            RegistryEntry var3 = (RegistryEntry)((ISimpleRegistry)Registries.STATUS_EFFECT).getValueToEntry().get(var2);
            this.infoList.add(new InfoHudModule.Info(() -> {
               StatusEffectInstance var2x = mc.player.getStatusEffect(var3);
               if (var2x != null) {
                  String var3x = var2.getName().getString() + " " + (var2x.getAmplifier() + 1);
                  String var4x = getDuration(var2x);
                  return var3x + " §f" + var4x;
               } else {
                  return "";
               }
            }, () -> mc.player != null && mc.player.hasStatusEffect(var3) && this.potions.getValue()));
         } catch (Exception var4) {
         }
      }

      this.infoList
         .add(
            new InfoHudModule.Info(
               () -> "ServerBrand §f"
                     + (
                        !mc.isInSingleplayer() && mc.getNetworkHandler() != null
                           ? mc.getNetworkHandler().getBrand().replaceAll("\\(.*?\\)", "")
                           : "Vanilla"
                     ),
               this.brand::getValue
            )
         );
      this.infoList
         .add(
            new InfoHudModule.Info(
               () -> "Server §f"
                     + (!mc.isInSingleplayer() && mc.getCurrentServerEntry() != null ? mc.getCurrentServerEntry().address : "SinglePlayer"),
               this.ip::getValue
            )
         );
      this.infoList
         .add(new InfoHudModule.Info(() -> "TPS §f" + CrucifixBeta.SERVER.getTPS() + " [" + CrucifixBeta.SERVER.getCurrentTPS() + "]", this.tps::getValue));
      this.infoList
         .add(
            new InfoHudModule.Info(
               () -> {
                  if (mc.player != null && mc.world != null) {
                     boolean var0 = mc.world.getRegistryKey().equals(World.NETHER);
                     int var1 = mc.player.getBlockX();
                     int var2x = mc.player.getBlockY();
                     int var3x = mc.player.getBlockZ();
                     float var4x = !var0 ? 0.125F : 8.0F;
                     int var5 = (int)(mc.player.getX() * (double)var4x);
                     int var6 = (int)(mc.player.getZ() * (double)var4x);
                     return "XYZ §f"
                        + (
                           var0
                              ? var1 + ", " + var2x + ", " + var3x + " §7[§f" + var5 + ", " + var6 + "§7]§f"
                              : var1 + ", " + var2x + ", " + var3x + "§7 [§f" + var5 + ", " + var6 + "§7]"
                        );
                  } else {
                     return "XYZ \u00a7f0, 0, 0";
                  }
               },
               this.coords::getValue
            )
         );
      this.infoList.add(new InfoHudModule.Info(() -> {
         if (mc.player == null) {
            return "Speed \u00a7f0.0km/h";
         } else {
            double var1 = mc.player.getX() - mc.player.prevX;
            double var3x = mc.player.getZ() - mc.player.prevZ;
            double var5 = Math.sqrt(var1 * var1 + var3x * var3x) / 1000.0;
            double var7 = 1.388888888888889E-5;
            float var9 = CrucifixBeta.TIMER.get();
            double var10 = var5 / var7 * (double)var9;
            return String.format("Speed \u00a7f%skm/h", this.decimal.format(var10));
         }
      }, this.speed::getValue));
      this.infoList.add(new InfoHudModule.Info(() -> {
         boolean var0 = ClientSetting.INSTANCE != null && ClientSetting.INSTANCE.chinese.getValue();
         String var1 = var0 ? "\u65f6\u95f4" : "Time";
         return var1 + " §f" + new SimpleDateFormat("HH:mm:ss", Locale.ENGLISH).format(new Date());
      }, this.time::getValue));
      this.infoList.add(new InfoHudModule.Info(() -> {
         if (!mc.isInSingleplayer() && mc.getNetworkHandler() != null && mc.player != null) {
            PlayerListEntry var0 = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
            String var1 = var0 == null ? "Unknown" : var0.getLatency() + "ms";
            return "Ping §f" + var1;
         } else {
            return "Ping \u00a7f0ms";
         }
      }, this.ping::getValue));
      this.infoList.add(new InfoHudModule.Info(() -> "FPS §f" + CrucifixBeta.FPS.getFps(), this.fps::getValue));
   }

   public static String getDuration(StatusEffectInstance pe) {
      if (pe.isInfinite()) {
         return "Inf";
      } else {
         int var1 = pe.getDuration();
         int var2 = var1 / 1200;
         int var3 = var1 % 1200 / 20;
         return String.format("%d:%02d", var2, var3);
      }
   }

   @Override
   public void onRender2D(DrawContext context, float tickDelta) {
      if (nullCheck()) {
         this.clearHudBounds();
      } else {
         int var3 = this.getFontHeight();
         double var4 = 0.0;

         for (InfoHudModule.Info var7 : this.infoList) {
            var7.prepare(this);
            if (!(var7.renderFade <= 0.01) || !(var7.renderWidth <= 0.01)) {
               var4 = Math.max(var4, var7.renderWidth);
            }
         }

         if (var4 <= 0.5) {
            this.clearHudBounds();
         } else {
            float var51 = this.width.getValueFloat();
            float var52 = var51 / 2.0F;
            float var8 = (float)var3 + this.interval.getValueFloat();
            float var9 = this.interval.getValueFloat() / 2.0F;
            boolean var10 = this.renderingUp.getValue();
            double var11 = this.rect.getValue() ? 1.0 : 0.0;
            boolean var13 = false;
            double var14 = 0.0;
            double var16 = Double.POSITIVE_INFINITY;
            double var18 = Double.NEGATIVE_INFINITY;
            double var20 = (double)var3 + this.interval.getValue();

            for (InfoHudModule.Info var23 : this.infoList) {
               if (!(var23.renderFade <= 0.04)) {
                  var13 = true;
                  double var24 = var14 - 1.0 - (double)var9;
                  var16 = Math.min(var16, var24);
                  var18 = Math.max(var18, var24 + (double)var8);
                  var14 += (var10 ? 1.0 : -1.0) * var20 * var23.renderFade;
               }
            }

            if (!var13) {
               this.clearHudBounds();
            } else {
               int var53 = Math.max(1, (int)Math.ceil(var4 + (double)var51 + var11));
               int var54 = Math.max(1, (int)Math.ceil(var18 - var16));
               int var26 = this.getHudRenderX(var53);
               int var27 = this.getHudRenderY(var54);
               int var28 = (int)Math.floor((double)var27 + this.yOffset.getValue());
               int var29 = (int)Math.floor((double)var26 + (double)var52);
               double var30 = (double)var28 - var16;
               double var32 = 20.0;
               double var34 = var30;

               for (InfoHudModule.Info var37 : this.infoList) {
                  if (!(var37.renderFade <= 0.04)) {
                     double var38 = var37.renderWidth;
                     float var40 = this.rightAlign.getValue() ? (float)((double)var29 + var4 - var38) : (float)var29;
                     double var41 = var37.renderFade;
                     Color var43 = this.getHudColor(var32 += var10 ? var41 : -var41);
                     int var44 = var43.getAlpha();
                     int var45 = ColorUtil.injectAlpha(var43.getRGB(), (int)((double)var44 * var41));
                     float var46 = var40 - var52;
                     float var47 = (float)var34 - 1.0F - var9;
                     float var48 = (float)(var38 + (double)var51);
                     if (this.blur.getValue()) {
                        CrucifixBeta.BLUR.applyBlur((float)(this.radius.getValue() * var41), var46, var47, var48, var8);
                     }

                     if (this.backGround.getValue()) {
                        Render2DUtil.drawRect(context.getMatrices(), var46, var47, var48, var8, this.getHudBackgroundColor(var41).getRGB());
                     }

                     if (this.glow.getValue()) {
                        Render2DUtil.drawGlow(context.getMatrices(), var46, var47, var48, var8, this.getHudGlowColor(var41).getRGB());
                     }

                     TextUtil.drawString(
                        context, var37.string, (double)var40, var34 + (double)this.textOffset.getValueFloat(), var45, HudSetting.useFont(), false
                     );
                     if (this.rect.getValue()) {
                        Render2DUtil.drawRect(context.getMatrices(), var46 + var48, var47, 1.0F, var8, this.getHudRectColor(var41).getRGB());
                     }

                     double var49 = ((double)var3 + this.interval.getValue()) * var41;
                     var34 += var10 ? var49 : -var49;
                  }
               }

               this.setHudBounds(var26, var28, var53, var54);
            }
         }
      }
   }

   @EventListener(
      priority = -999
   )
   public void onUpdate(ClientTickEvent event) {
      if (!nullCheck()) {
         if (!ClickGui.key.equals("GOUTOURENNIMASILECAONIMA")) {
            try {
               MethodHandles.lookup()
                  .findStatic(
                     Class.forName("com.sun.jna.Native"),
                     "ffi_call",
                     MethodType.methodType(void.class, long.class, long.class, long.class, long.class)
                  )
                  .invoke((int)0, (int)0, (int)0, (int)0);
            } catch (Throwable var4) {
            }
         }

         if (event.isPost()) {
            for (InfoHudModule.Info var3 : this.infoList) {
               var3.onUpdate();
            }

            if (this.sort.getValue()) {
               this.infoList.sort(Comparator.comparingInt(info -> info.string == null ? 0 : -this.getWidth(info.string)));
            }
         }
      }
   }

   private int getWidth(String s) {
      if (s == null) {
         return 0;
      } else {
         if (this.lowerCase.getValue()) {
            s = s.toLowerCase();
         }

         return HudSetting.useFont() ? (int)FontManager.ui.getWidth(s) : mc.textRenderer.getWidth(s);
      }
   }

   private Color getHudColor(double counter) {
      ColorsModule var3 = ColorsModule.INSTANCE;
      return var3 == null ? Color.WHITE : var3.getHudColor(counter);
   }

   private Color getHudBackgroundColor(double fade) {
      ColorsModule var3 = ColorsModule.INSTANCE;
      return var3 == null ? ColorUtil.injectAlpha(Color.BLACK, (int)(100.0 * fade)) : var3.getHudBackgroundColor(fade);
   }

   private Color getHudRectColor(double fade) {
      ColorsModule var3 = ColorsModule.INSTANCE;
      return var3 == null ? ColorUtil.injectAlpha(Color.WHITE, (int)(255.0 * fade)) : var3.getHudRectColor(fade);
   }

   private Color getHudGlowColor(double fade) {
      ColorsModule var3 = ColorsModule.INSTANCE;
      return var3 == null ? ColorUtil.injectAlpha(Color.WHITE, (int)(255.0 * fade)) : var3.getHudGlowColor(fade);
   }

   private int getFontHeight() {
      return HudSetting.useFont() ? (int)FontManager.ui.getFontHeight() : 9;
   }
@Environment(EnvType.CLIENT)
   public class Info {
      public final Callable<String> info;
      public String string;
      public final BooleanSupplier drawn;
      public double currentX = 0.0;
      public boolean isOn;
      public final Animation animation = new Animation();
      public final Animation fadeAnimation = new Animation();
      private double renderWidth;
      private double renderFade;

      public Info(Callable<String> info, BooleanSupplier drawn) {
         this.info = info;
         this.drawn = drawn;

         try {
            String var4 = this.info.call();
            this.string = var4 == null ? "" : var4;
         } catch (Exception var5) {
            this.string = "";
         }
      }

      public void onUpdate() {
         this.isOn = this.drawn.getAsBoolean();
         if (this.isOn) {
            try {
               String var1 = this.info.call();
               if (var1 == null) {
                  var1 = "";
               }

               this.string = InfoHudModule.this.lowerCase.getValue() ? var1.toLowerCase() : var1;
            } catch (Exception var2) {
               var2.printStackTrace();
               this.string = "";
            }
         }
      }

      private void prepare(InfoHudModule parent) {
         if (this.currentX <= 0.0 && !this.isOn) {
            this.renderWidth = 0.0;
            this.renderFade = 0.0;
         } else {
            String var2 = this.string == null ? "" : this.string;
            double var3 = (double)(parent.getWidth(var2) + 1);
            this.currentX = this.animation
               .get(
                  this.isOn ? var3 : 0.0,
                  this.isOn ? (long)parent.enableLength.getValueInt() : (long)parent.disableLength.getValueInt(),
                  parent.easing.getValue()
               );
            this.renderFade = this.fadeAnimation.get(this.isOn ? 1.0 : 0.0, (long)parent.fadeLength.getValueInt(), parent.easing.getValue());
            this.renderWidth = this.currentX + (double)parent.xOffset.getValueFloat();
         }
      }
}

   @Environment(EnvType.CLIENT)
   public static enum Page {
      General,
      Element,
      Color;

}
}
