package net.vulkanmod.render.chunk.build.frapi.helper;

import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.minecraft.class_2350;
import net.minecraft.class_3532;
import net.minecraft.class_2350.class_2351;
import net.minecraft.class_2350.class_2352;
import org.joml.Vector3fc;

public abstract class GeometryHelper {
   public static final int CUBIC_FLAG = 1;
   public static final int AXIS_ALIGNED_FLAG = 2;
   public static final int LIGHT_FACE_FLAG = 4;
   public static final int FLAG_BIT_COUNT = 3;
   private static final float EPS_MIN = 1.0E-4F;
   private static final float EPS_MAX = 0.9999F;

   private GeometryHelper() {
   }

   public static int computeShapeFlags(QuadView quad) {
      class_2350 lightFace = quad.lightFace();
      int bits = 0;
      if (isQuadParallelToFace(lightFace, quad)) {
         bits |= 2;
         if (isParallelQuadOnFace(lightFace, quad)) {
            bits |= 4;
         }
      }

      if (isQuadCubic(lightFace, quad)) {
         bits |= 1;
      }

      return bits;
   }

   public static boolean isQuadParallelToFace(class_2350 face, QuadView quad) {
      int i = face.method_10166().ordinal();
      float val = quad.posByIndex(0, i);
      return class_3532.method_15347(val, quad.posByIndex(1, i)) && class_3532.method_15347(val, quad.posByIndex(2, i)) && class_3532.method_15347(val, quad.posByIndex(3, i));
   }

   public static boolean isParallelQuadOnFace(class_2350 lightFace, QuadView quad) {
      float x = quad.posByIndex(0, lightFace.method_10166().ordinal());
      return lightFace.method_10171() == class_2352.field_11056 ? x >= 0.9999F : x <= 1.0E-4F;
   }

   public static boolean isQuadCubic(class_2350 lightFace, QuadView quad) {
      int a;
      int b;
      switch (lightFace) {
         case field_11034:
         case field_11039:
            a = 1;
            b = 2;
            break;
         case field_11036:
         case field_11033:
            a = 0;
            b = 2;
            break;
         case field_11035:
         case field_11043:
            a = 1;
            b = 0;
            break;
         default:
            return false;
      }

      return confirmSquareCorners(a, b, quad);
   }

   private static boolean confirmSquareCorners(int aCoordinate, int bCoordinate, QuadView quad) {
      int flags = 0;

      for(int i = 0; i < 4; ++i) {
         float a = quad.posByIndex(i, aCoordinate);
         float b = quad.posByIndex(i, bCoordinate);
         if (a <= 1.0E-4F) {
            if (b <= 1.0E-4F) {
               flags |= 1;
            } else {
               if (!(b >= 0.9999F)) {
                  return false;
               }

               flags |= 2;
            }
         } else {
            if (!(a >= 0.9999F)) {
               return false;
            }

            if (b <= 1.0E-4F) {
               flags |= 4;
            } else {
               if (!(b >= 0.9999F)) {
                  return false;
               }

               flags |= 8;
            }
         }
      }

      return flags == 15;
   }

   public static class_2350 lightFace(QuadView quad) {
      Vector3fc normal = quad.faceNormal();
      switch (longestAxis(normal)) {
         case field_11048 -> {
            return normal.x() > 0.0F ? class_2350.field_11034 : class_2350.field_11039;
         }
         case field_11052 -> {
            return normal.y() > 0.0F ? class_2350.field_11036 : class_2350.field_11033;
         }
         case field_11051 -> {
            return normal.z() > 0.0F ? class_2350.field_11035 : class_2350.field_11043;
         }
         default -> {
            return class_2350.field_11036;
         }
      }
   }

   public static float min(float a, float b, float c, float d) {
      float x = a < b ? a : b;
      float y = c < d ? c : d;
      return x < y ? x : y;
   }

   public static float max(float a, float b, float c, float d) {
      float x = a > b ? a : b;
      float y = c > d ? c : d;
      return x > y ? x : y;
   }

   public static class_2350.class_2351 longestAxis(Vector3fc vec) {
      return longestAxis(vec.x(), vec.y(), vec.z());
   }

   public static class_2350.class_2351 longestAxis(float normalX, float normalY, float normalZ) {
      class_2350.class_2351 result = class_2351.field_11052;
      float longest = Math.abs(normalY);
      float a = Math.abs(normalX);
      if (a > longest) {
         result = class_2351.field_11048;
         longest = a;
      }

      return Math.abs(normalZ) > longest ? class_2351.field_11051 : result;
   }
}
