package dev.crucifixbeta.mod.modules.impl.player;

import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.PacketEvent;
import dev.crucifixbeta.api.events.impl.UpdateEvent;
import dev.crucifixbeta.api.utils.math.Easing;
import dev.crucifixbeta.api.utils.math.FadeUtils;
import dev.crucifixbeta.api.utils.math.Timer;
import dev.crucifixbeta.api.utils.player.EntityUtil;
import dev.crucifixbeta.api.utils.player.MovementUtil;
import dev.crucifixbeta.mod.modules.Module;
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 java.awt.Color;
import java.text.DecimalFormat;
import java.util.Objects;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket;

@Environment(EnvType.CLIENT)
public class TimerModule extends Module {
   public static TimerModule INSTANCE;
   public final SliderSetting multiplier = this.add(new SliderSetting("Speed", 1.0, 0.1, 5.0, 0.01));
   public final BindSetting boostKey = this.add(new BindSetting("HoldKey", -1));
   public final SliderSetting boost = this.add(new SliderSetting("OnKey", 1.0, 0.1, 10.0, 0.01));
   final DecimalFormat df = new DecimalFormat("0.0");
   private final BooleanSetting tickShift = this.add(new BooleanSetting("TickShift", true).setParent());
   private final SliderSetting shiftTimer = this.add(new SliderSetting("ShiftTimer", 2.0, 1.0, 10.0, 0.1, this.tickShift::isOpen));
   private final SliderSetting accumulate = this.add(
      new SliderSetting("Charge", 2000.0, 1.0, 10000.0, 50.0, this.tickShift::isOpen).setSuffix("ms")
   );
   private final SliderSetting minAccumulate = this.add(
      new SliderSetting("MinCharge", 500.0, 1.0, 10000.0, 50.0, this.tickShift::isOpen).setSuffix("ms")
   );
   private final BooleanSetting smooth = this.add(new BooleanSetting("Smooth", true, this.tickShift::isOpen).setParent());
   private final EnumSetting<Easing> ease = this.add(
      new EnumSetting<>("Ease", Easing.CubicInOut, () -> this.smooth.isOpen() && this.tickShift.isOpen())
   );
   private final BooleanSetting reset = this.add(new BooleanSetting("Reset", true, this.tickShift::isOpen));
   private final BooleanSetting indicator = this.add(new BooleanSetting("Indicator", true, this.tickShift::isOpen).setParent());
   private final ColorSetting work = this.add(
      new ColorSetting("Completed", new Color(0, 255, 0), () -> this.indicator.isOpen() && this.tickShift.isOpen())
   );
   private final ColorSetting charging = this.add(
      new ColorSetting("Charging", new Color(255, 0, 0), () -> this.indicator.isOpen() && this.tickShift.isOpen())
   );
   private final SliderSetting yOffset = this.add(
      new SliderSetting("YOffset", 0.0, -200.0, 200.0, 1.0, () -> this.indicator.isOpen() && this.tickShift.isOpen())
   );
   private final Timer timer = new Timer();
   private final Timer timer2 = new Timer();
   private final FadeUtils end = new FadeUtils(500L);
   long lastMs = 0L;
   boolean moving = false;

   public TimerModule() {
      super("Timer", Module.Category.Player);
      this.setChinese("\u65f6\u95f4\u52a0\u901f");
      INSTANCE = this;
   }

   @Override
   public void onDisable() {
      CrucifixBeta.TIMER.reset();
   }

   @EventListener
   public void onUpdate(UpdateEvent event) {
      CrucifixBeta.TIMER.tryReset();
   }

   @Override
   public void onEnable() {
      CrucifixBeta.TIMER.reset();
   }

   @Override
   public void onRender2D(DrawContext drawContext, float tickDelta) {
      if (this.tickShift.getValue()) {
         this.timer.setMs(Math.min(Math.max(0L, this.timer.getMs()), (long)this.accumulate.getValueInt()));
         if (MovementUtil.isMoving() && !EntityUtil.isInsideBlock()) {
            if (!this.moving) {
               if (this.timer.passedMs(this.minAccumulate.getValue())) {
                  this.timer2.reset();
                  this.lastMs = this.timer.getMs();
               } else {
                  this.lastMs = 0L;
               }

               this.moving = true;
            }

            this.timer.reset();
            if (this.timer2.passed(this.lastMs)) {
               CrucifixBeta.TIMER.reset();
            } else if (this.smooth.getValue()) {
               double var3 = (double)CrucifixBeta.TIMER.getDefault()
                  + (1.0 - this.end.ease(this.ease.getValue()))
                     * (double)(this.shiftTimer.getValueFloat() - 1.0F)
                     * ((double)this.lastMs / this.accumulate.getValue());
               CrucifixBeta.TIMER.set((float)Math.max((double)CrucifixBeta.TIMER.getDefault(), var3));
            } else {
               CrucifixBeta.TIMER.set(this.shiftTimer.getValueFloat());
            }
         } else {
            if (this.moving) {
               CrucifixBeta.TIMER.reset();
               if (this.reset.getValue()) {
                  this.timer.reset();
               } else {
                  this.timer.setMs(Math.max(this.lastMs - this.timer2.getMs(), 0L));
               }

               this.moving = false;
            }

            this.end.setLength(this.timer.getMs());
            this.end.reset();
         }

         if (this.indicator.getValue()) {
            double var12 = this.moving ? (double)Math.max(this.lastMs - this.timer2.getMs(), 0L) : (double)this.timer.getMs();
            boolean var5 = this.moving && var12 > 0.0 || var12 >= (double)this.minAccumulate.getValueInt();
            double var6 = this.accumulate.getValue();
            String var8 = this.df.format(var12 / var6 * 100.0) + "%";
            TextRenderer var9 = mc.textRenderer;
            int var10 = mc.getWindow().getScaledWidth() / 2 - mc.textRenderer.getWidth(var8) / 2;
            int var11 = mc.getWindow().getScaledHeight() / 2;
            Objects.requireNonNull(mc.textRenderer);
            drawContext.drawText(
               var9, var8, var10, var11 + 9 - this.yOffset.getValueInt(), var5 ? this.work.getValue().getRGB() : this.charging.getValue().getRGB(), false
            );
         }
      }
   }

   @Override
   public String getInfo() {
      if (!this.tickShift.getValue()) {
         return null;
      } else {
         double var1 = this.moving ? (double)Math.max(this.lastMs - this.timer2.getMs(), 0L) : (double)this.timer.getMs();
         double var3 = this.accumulate.getValue();
         double var5 = Math.min(var1 / var3 * 100.0, 100.0);
         return this.df.format(var5) + "%";
      }
   }

   @EventListener
   public void onReceivePacket(PacketEvent.Receive event) {
      if (event.getPacket() instanceof PlayerPositionLookS2CPacket) {
         this.lastMs = 0L;
      }
   }
}
