package wtf.opal.client.renderer.text;

import com.google.common.collect.Lists;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.lwjgl.nanovg.NanoVG;
import org.lwjgl.system.MemoryStack;
import wtf.opal.client.Constants;
import wtf.opal.client.renderer.NVGRenderer;
import wtf.opal.utility.misc.system.IOUtility;
import wtf.opal.utility.render.ColorUtility;

@Environment(EnvType.CLIENT)
public final class NVGTextRenderer {
   private static final int DEFAULT_ALIGNMENT;
   public static boolean blockTextRendering;
   private final String name;
   private final ByteBuffer fontData;
   private static final int WIDTH_CACHE_LIMIT;
   private final Map<Integer, LinkedHashMap<String, Float>> widthCache = new HashMap<>();
   private static final int[] COLOR_CODES;
   private static final char COLOR_INVOKER;
   private static final byte[] CHAR_TO_INDEX;

   public NVGTextRenderer(String name, InputStream inputStream) {
      this.name = name;
      this.fontData = IOUtility.ioResourceToByteBuffer(inputStream, 524288);
      if (this.fontData != null) {
         NanoVG.nvgCreateFontMem(Constants.VG, this.name, this.fontData, false);
      }
   }

   public List<String> wrapStringToWidth(String text, float width, float size) {
      float var4 = 0.0F;
      StringBuilder var5 = new StringBuilder();
      ArrayList var6 = new ArrayList();
      ArrayList var7 = Lists.newArrayList(new String[]{text});

      for (int var8 = 0; var8 < var7.size() && var8 < 1024; var8++) {
         String var9 = (String)var7.get(var8);
         boolean var10 = false;
         if (text.contains("\n")) {
            int var11 = text.indexOf(10);
            String var12 = text.substring(var11 + 1);
            text = text.substring(0, var11 + 1);
            var7.add(var8 + 1, var12);
            var10 = true;
         }

         String var17 = var9.endsWith("\n") ? var9.substring(0, var9.length() - 1) : var9;
         float var18 = this.getStringWidth(var17, size);
         String var13 = var17;
         if (var4 + var18 > width) {
            String var14 = this.trimStringToWidth(var9, width - var4, size);
            String var15 = var14.length() < var9.length() ? var9.substring(var14.length()) : null;
            if (var15 != null) {
               int var16 = var14.lastIndexOf(32);
               if (var16 >= 0 && this.getStringWidth(var9.substring(0, var16), size) > 0.0F) {
                  var14 = var9.substring(0, var16);
                  var15 = var9.substring(var16);
               } else if (var4 > 0.0F && !var9.contains(" ")) {
                  var14 = "";
                  var15 = var9;
               }

               if (!var15.isEmpty() && var15.charAt(0) == ' ') {
                  var14 = var14 + " ";
                  var15 = var15.substring(1);
               }

               var7.add(var8 + 1, var15);
            }

            var18 = this.getStringWidth(var14, size);
            var13 = var14;
            var10 = true;
         }

         if (var4 + var18 <= width) {
            var4 += var18;
            var5.append(var13);
         } else {
            var10 = true;
         }

         if (var10) {
            var6.add(var5.toString());
            var4 = 0.0F;
            var5 = new StringBuilder();
         }
      }

      var6.add(var5.toString());
      return var6;
   }

   public String trimStringToWidth(String text, float width, float size) {
      StringBuilder var4 = new StringBuilder();
      float var5 = 0.0F;
      byte var6 = 0;
      byte var7 = 1;
      boolean var8 = false;
      boolean var9 = false;

      for (int var10 = var6; var10 >= 0 && var10 < text.length() && var5 < width; var10 += var7) {
         char var11 = text.charAt(var10);
         float var12 = this.getStringWidth(String.valueOf(var11), size);
         if (var11 == 167) {
            var4.append(var11);
            if (var10 != text.length() - 1) {
               var4.append(text.charAt(var10 + 1));
            }

            var10++;
         } else {
            if (var8) {
               var8 = false;
               if (var11 == 'l' || var11 == 'L') {
                  var9 = true;
               } else if (var11 == 'r' || var11 == 'R') {
                  var9 = false;
               }
            } else if (var12 < 0.0F) {
               var8 = true;
            } else {
               var5 += var12;
               if (var9) {
                  var5++;
               }
            }

            if (var5 > width) {
               break;
            }

            var4.append(var11);
         }
      }

      return var4.toString();
   }

   public float drawStringWithShadow(String text, float x, float y, float size, int color) {
      this.drawString(text, x + 0.5F, y + 0.5F, size, color, true, 3);
      return this.drawString(text, x, y, size, color, false, 3);
   }

   public float drawString(String text, float x, float y, float size, int color) {
      return this.drawString(text, x, y, size, color, false, 3);
   }

   public void drawGradientString(String text, float x, float y, float size, int color1, int color2, boolean shadow) {
      if (!blockTextRendering) {
         float var8 = 0.0F;

         for (int var9 = 0; var9 < text.length(); var9++) {
            char var10 = text.charAt(var9);
            String var11 = String.valueOf(var10);
            float var12 = this.getStringWidth(var11, size);
            int var13 = ColorUtility.interpolateColorsBackAndForth(10, var9 * 15, color1, color2);
            if (shadow) {
               this.drawStringWithShadow(var11, x + var8, y, size, var13);
            } else {
               this.drawString(var11, x + var8, y, size, var13);
            }

            var8 += var12;
         }
      }
   }

   public void drawGradientString(String text, float x, float y, float size, int color1, int color2) {
      this.drawGradientString(text, x, y, size, color1, color2, false);
   }

   public void drawGradientStringWithShadow(String text, float x, float y, float size, int color1, int color2) {
      this.drawGradientString(text, x, y, size, color1, color2, true);
   }

   public float drawString(String text, float x, float y, float size, int color, boolean shadow, int alignment) {
      if (blockTextRendering) {
         return x;
      } else {
         NanoVG.nvgBeginPath(Constants.VG);
         NanoVG.nvgFontFace(Constants.VG, this.name);
         NanoVG.nvgFontSize(Constants.VG, size);
         NanoVG.nvgTextAlign(Constants.VG, alignment);
         boolean var8 = false;
         boolean var9 = false;
         NVGRenderer.applyColor(shadow ? ColorUtility.getShadowColor(color) : color, NVGRenderer.NVG_COLOR_1);
         NanoVG.nvgFillColor(Constants.VG, NVGRenderer.NVG_COLOR_1);
         StringBuilder var10 = new StringBuilder();

         for (int var11 = 0; var11 < text.length(); var11++) {
            char var12 = text.charAt(var11);
            if (var12 == 167 && text.length() > var11 + 1) {
               if (!var10.isEmpty()) {
                  String var13 = var10.toString();
                  this.drawStringSegment(var13, x, y, size, var8, var9);
                  x += this.getStringWidth(var13, size);
                  var10.setLength(0);
               }

               int var16 = this.getColorCodeCharacter(Character.toLowerCase(text.charAt(var11 + 1)));
               if (var16 >= 0) {
                  if (var16 < 16) {
                     NanoVG.nvgFontFace(Constants.VG, this.name);
                     var9 = false;
                     var8 = false;
                     int var14 = COLOR_CODES[var16];
                     if (shadow) {
                        var14 = ColorUtility.getShadowColor(var14);
                     }

                     NVGRenderer.applyColor(ColorUtility.applyOpacity(var14, color >> 24 & 0xFF), NVGRenderer.NVG_COLOR_2);
                     NanoVG.nvgFillColor(Constants.VG, NVGRenderer.NVG_COLOR_2);
                  } else {
                     switch (var16) {
                        case 17:
                        case 20:
                           break;
                        case 18:
                           var9 = true;
                           break;
                        case 19:
                           var8 = true;
                           break;
                        default:
                           var9 = false;
                           var8 = false;
                           NanoVG.nvgFillColor(Constants.VG, NVGRenderer.NVG_COLOR_1);
                     }
                  }
               }

               var11++;
            } else {
               var10.append(var12);
            }
         }

         if (!var10.isEmpty()) {
            String var15 = var10.toString();
            this.drawStringSegment(var15, x, y, size, var8, var9);
            x += this.getStringWidth(var15, size);
         }

         NanoVG.nvgClosePath(Constants.VG);
         return x;
      }
   }

   private int getColorCodeCharacter(char lowerCase) {
      return lowerCase < 128 ? CHAR_TO_INDEX[lowerCase] : -1;
   }

   private void drawStringSegment(String segment, float x, float y, float size, boolean underline, boolean strikethrough) {
      NanoVG.nvgText(Constants.VG, x, y, segment);
      if (underline || strikethrough) {
         float var7 = this.getStringWidth(segment, size);
         if (strikethrough) {
            float var8 = y - size * 0.25F;
            NanoVG.nvgBeginPath(Constants.VG);
            NanoVG.nvgMoveTo(Constants.VG, x, var8);
            NanoVG.nvgLineTo(Constants.VG, x + var7, var8 + 0.5F);
            NanoVG.nvgFill(Constants.VG);
            NanoVG.nvgClosePath(Constants.VG);
         }

         if (underline) {
            NanoVG.nvgBeginPath(Constants.VG);
            NanoVG.nvgMoveTo(Constants.VG, x, y);
            NanoVG.nvgLineTo(Constants.VG, x + var7, y + 0.5F);
            NanoVG.nvgFill(Constants.VG);
            NanoVG.nvgClosePath(Constants.VG);
         }
      }
   }

   public float getStringWidth(String text, float size) {
      if (text != null && !text.isEmpty()) {
         int var3 = Float.floatToIntBits(size);
         LinkedHashMap var4 = this.widthCache.computeIfAbsent(var3, ignored -> new LinkedHashMap<String, Float>(128, 0.75F, true) {
               @Override
               protected boolean removeEldestEntry(Entry<String, Float> eldest) {
                  return this.size() > 2048;
               }
            });
         Float var5 = (Float)var4.get(text);
         if (var5 != null) {
            return var5;
         } else {
            NanoVG.nvgFontFace(Constants.VG, this.name);
            NanoVG.nvgFontSize(Constants.VG, size);
            StringBuilder var6 = new StringBuilder();
            float var7 = 0.0F;
            int var8 = text.length();

            for (int var9 = 0; var9 < var8; var9++) {
               char var10 = text.charAt(var9);
               if (var10 == 167 && var9 < var8 - 1) {
                  var9++;
               } else {
                  var6.append(var10);
               }

               if ((var10 == 167 && var9 < var8 - 1 || var9 == var8 - 1) && !var6.isEmpty()) {
                  var7 += NanoVG.nvgTextBounds(Constants.VG, 0.0F, 0.0F, var6.toString(), (FloatBuffer)null);
                  var6.setLength(0);
               }
            }

            var4.put(text, Float.valueOf(var7));
            return var7;
         }
      } else {
         return 0.0F;
      }
   }

   public float getStringHeight(String text, float size) {
      NanoVG.nvgFontFace(Constants.VG, this.name);
      NanoVG.nvgFontSize(Constants.VG, size);
      MemoryStack var3 = MemoryStack.stackPush();

      float var5;
      try {
         FloatBuffer var4 = var3.mallocFloat(4);
         NanoVG.nvgTextBounds(Constants.VG, 0.0F, 0.0F, text, var4);
         var5 = var4.get(3) - var4.get(1);
      } catch (Throwable var7) {
         if (var3 != null) {
            try {
               var3.close();
            } catch (Throwable var6) {
               var7.addSuppressed(var6);
            }
         }

         throw var7;
      }

      if (var3 != null) {
         var3.close();
      }

      return var5;
   }

   private static void initColorCodes() {
      for (int var0 = 0; var0 < 32; var0++) {
         int var1 = (var0 >> 3 & 1) * 85;
         int var2 = (var0 >> 2 & 1) * 170 + var1;
         int var3 = (var0 >> 1 & 1) * 170 + var1;
         int var4 = (var0 & 1) * 170 + var1;
         if (var0 == 6) {
            var2 += 85;
         }

         if (var0 >= 16) {
            var2 /= 4;
            var3 /= 4;
            var4 /= 4;
         }

         COLOR_CODES[var0] = (var2 & 0xFF) << 16 | (var3 & 0xFF) << 8 | var4 & 0xFF;
      }

      String var5 = "0123456789abcdefklmnor";

      for (int var6 = 0; var6 < 128; var6++) {
         CHAR_TO_INDEX[var6] = -1;
      }

      for (int var7 = 0; var7 < ("0123456789abcdefklmnor").length(); var7++) {
         char var8 = ("0123456789abcdefklmnor").charAt(var7);
         CHAR_TO_INDEX[var8] = (byte)var7;
         CHAR_TO_INDEX[Character.toLowerCase(var8)] = (byte)var7;
      }
   }

   static {

      COLOR_INVOKER = 167;
      WIDTH_CACHE_LIMIT = 2048;
      DEFAULT_ALIGNMENT = 3;
      COLOR_CODES = new int[32];
      CHAR_TO_INDEX = new byte[128];
      initColorCodes();
   }
}
