package asm.mixins;

import asm.accessors.IChatHud;
import com.llamalad7.mixinextras.sugar.Local;
import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.interfaces.IChatHudHook;
import dev.crucifixbeta.api.interfaces.IChatHudLineHook;
import dev.crucifixbeta.api.utils.math.FadeUtils;
import dev.crucifixbeta.api.utils.render.ColorUtil;
import dev.crucifixbeta.api.utils.render.Render2DUtil;
import dev.crucifixbeta.mod.modules.impl.client.ClientSetting;
import java.awt.Color;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.ChatHud;
import net.minecraft.client.gui.hud.ChatHudLine;
import net.minecraft.client.gui.hud.MessageIndicator;
import net.minecraft.client.gui.hud.ChatHudLine.Visible;
import net.minecraft.network.message.MessageSignatureData;
import net.minecraft.text.OrderedText;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Environment(EnvType.CLIENT)
@Mixin({ChatHud.class})
public abstract class MixinChatHud implements IChatHudHook {
   @Unique
   private int nextMessageId = 0;
   @Unique
   private boolean nextSync;
   @Unique
   private int chatLineIndex;
   @Final
   @Shadow
   private List<Visible> visibleMessages;
   @Shadow
   @Final
   private List<ChatHudLine> messages;
   @Shadow
   @Final
   private MinecraftClient client;

   @Inject(
      method = {"<init>"},
      at = {@At("TAIL")}
   )
   public void onInit(MinecraftClient client, CallbackInfo ci) {
      ((IChatHud)this).setMessages(new CopyOnWriteArrayList<>());
      ((IChatHud)this).setVisibleMessages(new CopyOnWriteArrayList<>());
   }

   @Override
   public void frogClient$addMessage(Text message, int id) {
      this.nextMessageId = id;
      this.nextSync = true;
      this.addMessage(message);
      this.nextSync = false;
      this.nextMessageId = 0;
   }

   @Override
   public void frogClient$addMessage(Text message) {
      this.nextSync = true;
      this.addMessage(message);
      this.nextSync = false;
   }

   @Override
   public void frogClient$addMessageOutSync(Text message, int id) {
      this.nextMessageId = id;
      this.addMessage(message);
      this.nextMessageId = 0;
   }

   @Inject(
      method = {"addVisibleMessage"},
      at = {@At(
         value = "INVOKE",
         target = "Ljava/util/List;add(ILjava/lang/Object;)V",
         ordinal = 0,
         shift = Shift.AFTER
      )}
   )
   private void onAddMessageAfterNewChatHudLineVisible(ChatHudLine message, CallbackInfo ci) {
      IChatHudLineHook var3 = (IChatHudLineHook)(Object)this.visibleMessages.getFirst();
      if (var3 != null) {
         var3.frogClient$setMessageId(this.nextMessageId);
         var3.frogClient$setSync(this.nextSync);
         var3.frogClient$setFade(new FadeUtils((long)ClientSetting.INSTANCE.animationTime.getValueInt()));
      }
   }

   @Inject(
      method = {"addMessage(Lnet/minecraft/client/gui/hud/ChatHudLine;)V"},
      at = {@At(
         value = "INVOKE",
         target = "Ljava/util/List;add(ILjava/lang/Object;)V",
         ordinal = 0,
         shift = Shift.AFTER
      )}
   )
   private void onAddMessageAfterNewChatHudLine(ChatHudLine message, CallbackInfo ci) {
      IChatHudLineHook var3 = (IChatHudLineHook)(Object)this.messages.getFirst();
      if (var3 != null) {
         var3.frogClient$setMessageId(this.nextMessageId);
         var3.frogClient$setSync(this.nextSync);
         var3.frogClient$setFade(new FadeUtils((long)ClientSetting.INSTANCE.animationTime.getValueInt()));
      }
   }

   @Inject(
      at = {@At("HEAD")},
      method = {"addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;Lnet/minecraft/client/gui/hud/MessageIndicator;)V"}
   )
   private void onAddMessage(Text message, MessageSignatureData signatureData, MessageIndicator indicator, CallbackInfo ci) {
      if (this.nextMessageId != 0) {
         this.visibleMessages.removeIf(msg -> ((IChatHudLineHook)(Object)msg).frogClient$getMessageId() == this.nextMessageId);
         this.messages.removeIf(msg -> ((IChatHudLineHook)(Object)msg).frogClient$getMessageId() == this.nextMessageId);
      }
   }

   @Redirect(
      method = {"addVisibleMessage"},
      at = @At(
         value = "INVOKE",
         target = "Ljava/util/List;size()I",
         ordinal = 2,
         remap = false
      ),
      require = 0
   )
   public int chatLinesSize(List<Visible> list) {
      return ClientSetting.INSTANCE.isOn() && ClientSetting.INSTANCE.infiniteChat.getValue() ? -2147483647 : list.size();
   }

   @Redirect(
      method = {"render"},
      at = @At(
         value = "INVOKE",
         target = "Lnet/minecraft/client/gui/DrawContext;drawTextWithShadow(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/OrderedText;III)I"
      ),
      require = 0
   )
   private int drawStringWithShadow(DrawContext drawContext, TextRenderer textRenderer, OrderedText text, int x, int y, int color) {
      IChatHudLineHook var7 = (IChatHudLineHook)(Object)this.visibleMessages.get(this.chatLineIndex);
      if (var7 != null) {
         FadeUtils var8 = var7.frogClient$getFade();
         double var9 = var8 == null ? 0.0 : var8.ease(ClientSetting.INSTANCE.ease.getValue());
         double var11 = 1.0 - var9;
         x += (int)(var11 * ClientSetting.INSTANCE.animateOffset.getValue());
         double var13 = Math.max(10.0, (double)(color >> 24 & 0xFF) * var9);
         return var7.frogClient$getSync()
            ? drawContext.drawText(
               textRenderer,
               text,
               x,
               y,
               ColorUtil.injectAlpha(ClientSetting.INSTANCE.color.getValue(), ClientSetting.INSTANCE.fade.getValue() ? (int)var13 : color >> 24 & 0xFF)
                  .getRGB(),
               false
            )
            : drawContext.drawText(
               textRenderer, text, x, y, ColorUtil.injectAlpha(color, ClientSetting.INSTANCE.fade.getValue() ? (int)var13 : color >> 24 & 0xFF), false
            );
      } else {
         return drawContext.drawText(textRenderer, text, x, y, color, false);
      }
   }

   @Redirect(
      method = {"render"},
      at = @At(
         value = "INVOKE",
         target = "Lnet/minecraft/client/gui/DrawContext;fill(IIIII)V",
         ordinal = 0
      ),
      require = 0
   )
   private void drawChatBackground(DrawContext context, int x1, int y1, int x2, int y2, int color) {
      ClientSetting var7 = ClientSetting.INSTANCE;
      if (var7 == null) {
         context.fill(x1, y1, x2, y2, color);
      } else {
         int var8 = this.getChatBackgroundColor(color, var7);
         boolean var9 = var7.chatBackgroundBlur.getValue();
         if (var8 >>> 24 > 0 || var9) {
            float var10 = (float)x1;
            float var11 = (float)y1;
            float var12 = (float)(x2 - x1);
            float var13 = (float)(y2 - y1);
            if (var9 && CrucifixBeta.BLUR != null) {
               float var14 = (float)this.getChatScale();
               CrucifixBeta.BLUR.applyBlur(var7.chatBackgroundBlurRadius.getValueFloat(), (var10 + 4.0F) * var14, var11 * var14, var12 * var14, var13 * var14);
            }

            if (var8 >>> 24 > 0) {
               float var15 = Math.min(var7.chatBackgroundRadius.getValueFloat(), Math.min(var12, var13) / 2.0F);
               if (var15 <= 0.0F) {
                  context.fill(x1, y1, x2, y2, var8);
               } else {
                  Render2DUtil.drawRoundedRect(context.getMatrices(), var10, var11, var12, var13, var15, new Color(var8, true));
               }
            }
         }
      }
   }

   private int getChatBackgroundColor(int vanillaColor, ClientSetting setting) {
      int var3 = Math.min(vanillaColor >>> 24, setting.chatBackgroundColor.getValue().getAlpha());
      Color var4 = setting.chatBackgroundColor.getValue();
      return new Color(var4.getRed(), var4.getGreen(), var4.getBlue(), var3).getRGB();
   }

   @Inject(
      method = {"render"},
      at = {@At(
         value = "INVOKE",
         target = "Lnet/minecraft/client/gui/hud/ChatHudLine$Visible;addedTime()I"
      )}
   )
   public void getChatLineIndex(CallbackInfo ci, @Local(ordinal = 13) int chatLineIndex) {
      this.chatLineIndex = chatLineIndex;
   }

   @ModifyVariable(
      method = {"render"},
      at = @At("STORE")
   )
   private MessageIndicator removeMessageIndicator(MessageIndicator messageIndicator) {
      return ClientSetting.INSTANCE.hideIndicator.getValue() ? null : messageIndicator;
   }

   @Shadow
   public abstract void addMessage(Text text);

   @Shadow
   public int getWidth() {
      return 0;
   }

   @Shadow
   public abstract double getChatScale();
}
