package dev.crucifixbeta.api.utils.render;

import dev.crucifixbeta.core.impl.FontManager;
import dev.crucifixbeta.mod.gui.fonts.FontRenderer;
import dev.crucifixbeta.mod.modules.impl.client.Fonts;
import java.util.ArrayList;
import java.util.List;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.font.TextRenderer.TextLayerType;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.VertexConsumerProvider.Immediate;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.OrderedText;
import net.minecraft.text.StringVisitable;
import net.minecraft.text.Style;
import net.minecraft.text.TextColor;
import org.joml.Matrix4f;

@Environment(EnvType.CLIENT)
public final class GlobalFontRenderer {
   private static final int FULL_BRIGHT_LIGHT = 15728880;
   private static boolean drawing;

   private GlobalFontRenderer() {
   }

   public static boolean shouldReplace() {
      return !drawing && FontManager.ui != null && Fonts.shouldReplaceMinecraftFont();
   }

   public static boolean shouldReplaceDraw(VertexConsumerProvider vertexConsumers, TextLayerType layerType, int backgroundColor, int light) {
      return shouldReplace() && vertexConsumers instanceof Immediate && layerType == TextLayerType.NORMAL && backgroundColor == 0 && light == 15728880;
   }

   public static void flush(VertexConsumerProvider vertexConsumers) {
      if (vertexConsumers instanceof Immediate var1) {
         var1.draw();
      }
   }

   public static int drawString(String text, float x, float y, int color, boolean shadow, Matrix4f matrix) {
      if (text != null && !text.isEmpty()) {
         MatrixStack var6 = stackFrom(matrix);
         drawString(var6, text, x, y, color, shadow);
         return (int)Math.ceil((double)(x + width(text)));
      } else {
         return (int)x;
      }
   }

   public static int drawOrderedText(OrderedText text, float x, float y, int color, boolean shadow, Matrix4f matrix) {
      if (text == null) {
         return (int)x;
      } else {
         List var6 = collectRuns(text, color);
         if (var6.isEmpty()) {
            return (int)x;
         } else {
            MatrixStack var7 = stackFrom(matrix);
            drawRuns(var7, var6, x, y, shadow);
            return (int)Math.ceil((double)(x + width(var6)));
         }
      }
   }

   public static int widthString(String text) {
      return (int)Math.ceil((double)width(text));
   }

   public static int widthOrderedText(OrderedText text) {
      return (int)Math.ceil((double)width(collectRuns(text, -1)));
   }

   public static int widthStringVisitable(StringVisitable text) {
      return text == null ? 0 : widthString(text.getString());
   }

   private static MatrixStack stackFrom(Matrix4f matrix) {
      MatrixStack var1 = new MatrixStack();
      var1.peek().getPositionMatrix().set(matrix);
      return var1;
   }

   private static void drawString(MatrixStack stack, String text, float x, float y, int color, boolean shadow) {
      FontRenderer var6 = FontManager.ui;
      if (var6 != null) {
         int var7 = normalizeColor(color);
         drawing = true;

         try {
            if (shadow) {
               var6.drawString(stack, FontRenderer.stripControlCodes(text), (double)(x + 1.0F), (double)(y + 1.0F), shadowColor(var7), false);
            }

            var6.drawString(stack, text, (double)x, (double)y, var7, false);
         } finally {
            drawing = false;
         }
      }
   }

   private static void drawRuns(MatrixStack stack, List<GlobalFontRenderer.TextRun> runs, float x, float y, boolean shadow) {
      FontRenderer var5 = FontManager.ui;
      if (var5 != null) {
         drawing = true;

         try {
            if (shadow) {
               float var6 = x;

               for (GlobalFontRenderer.TextRun var8 : runs) {
                  var5.drawString(stack, var8.text(), (double)(var6 + 1.0F), (double)(y + 1.0F), shadowColor(var8.color()), false);
                  var6 += width(var8.text());
               }
            }

            float var12 = x;

            for (GlobalFontRenderer.TextRun var14 : runs) {
               var5.drawString(stack, var14.text(), (double)var12, (double)y, var14.color(), false);
               var12 += width(var14.text());
            }
         } finally {
            drawing = false;
         }
      }
   }

   private static List<GlobalFontRenderer.TextRun> collectRuns(OrderedText text, int baseColor) {
      ArrayList var2 = new ArrayList();
      StringBuilder var3 = new StringBuilder();
      int[] var4 = new int[]{Integer.MIN_VALUE};
      int var5 = normalizeColor(baseColor);
      text.accept((index, style, codePoint) -> {
         int var7 = resolveColor(style, var5);
         if (var4[0] != var7) {
            appendRun(var2, var3, var4[0]);
            var4[0] = var7;
         }

         var3.appendCodePoint(codePoint);
         return true;
      });
      appendRun(var2, var3, var4[0]);
      return var2;
   }

   private static void appendRun(List<GlobalFontRenderer.TextRun> runs, StringBuilder text, int color) {
      if (!text.isEmpty()) {
         runs.add(new GlobalFontRenderer.TextRun(text.toString(), normalizeColor(color)));
         text.setLength(0);
      }
   }

   private static int resolveColor(Style style, int baseColor) {
      if (style == null) {
         return baseColor;
      } else {
         TextColor var2 = style.getColor();
         return var2 == null ? baseColor : baseColor & 0xFF000000 | var2.getRgb() & 16777215;
      }
   }

   private static float width(String text) {
      FontRenderer var1 = FontManager.ui;
      return var1 != null && text != null && !text.isEmpty() ? var1.getWidth(text) : 0.0F;
   }

   private static float width(List<GlobalFontRenderer.TextRun> runs) {
      float var1 = 0.0F;

      for (GlobalFontRenderer.TextRun var3 : runs) {
         var1 += width(var3.text());
      }

      return var1;
   }

   private static int normalizeColor(int color) {
      return (color & -67108864) == 0 ? color | 0xFF000000 : color;
   }

   private static int shadowColor(int color) {
      return color & 0xFF000000 | (color & 16579836) >> 2;
   }

   @Environment(EnvType.CLIENT)
   private static record TextRun(String text, int color) {
   }
}
