package net.vulkanmod.render.chunk.build.light.data;

import net.minecraft.class_1920;
import net.minecraft.class_1944;
import net.minecraft.class_2338;
import net.minecraft.class_265;
import net.minecraft.class_2680;
import net.minecraft.class_761;
import net.minecraft.class_765;
import net.minecraft.class_761.class_10948;
import net.vulkanmod.Initializer;
import net.vulkanmod.interfaces.VoxelShapeExtended;
import net.vulkanmod.render.chunk.util.SimpleDirection;

public abstract class LightDataAccess {
   private static final int BL_OFFSET = 0;
   private static final int SL_OFFSET = 4;
   private static final int AO_OFFSET = 8;
   private static final int CO_OFFSET = 20;
   private static final int EM_OFFSET = 28;
   private static final int OP_OFFSET = 29;
   private static final int FO_OFFSET = 30;
   private static final int FC_OFFSET = 31;
   private static final float AO_INV = 4.8828125E-4F;
   private final class_2338.class_2339 pos = new class_2338.class_2339();
   protected class_1920 region;
   final boolean subBlockLighting;

   protected LightDataAccess() {
      this.subBlockLighting = Initializer.CONFIG.ambientOcclusion == 2;
   }

   public int get(int x, int y, int z, SimpleDirection d1, SimpleDirection d2) {
      return this.get(x + d1.getStepX() + d2.getStepX(), y + d1.getStepY() + d2.getStepY(), z + d1.getStepZ() + d2.getStepZ());
   }

   public int get(int x, int y, int z, SimpleDirection dir) {
      return this.get(x + dir.getStepX(), y + dir.getStepY(), z + dir.getStepZ());
   }

   public int get(class_2338 pos, SimpleDirection dir) {
      return this.get(pos.method_10263(), pos.method_10264(), pos.method_10260(), dir);
   }

   public int get(class_2338 pos) {
      return this.get(pos.method_10263(), pos.method_10264(), pos.method_10260());
   }

   public abstract int get(int var1, int var2, int var3);

   protected int compute(int x, int y, int z) {
      class_2338 pos = this.pos.method_10103(x, y, z);
      class_2680 state = this.region.method_8320(pos);
      boolean em = state.method_26208(this.region, pos);
      boolean op;
      if (this.subBlockLighting) {
         op = state.method_26225();
      } else {
         op = state.method_26230(this.region, pos) && state.method_26193() != 0;
      }

      boolean fo = state.method_26216();
      boolean fc = state.method_26234(this.region, pos);
      int lu = state.method_26213();
      int bl;
      int sl;
      if (fo && lu == 0) {
         bl = 0;
         sl = 0;
      } else if (em) {
         bl = this.region.method_8314(class_1944.field_9282, pos);
         sl = this.region.method_8314(class_1944.field_9284, pos);
      } else {
         int light = class_761.method_23793(class_10948.field_58200, this.region, state, pos);
         bl = class_765.method_24186(light);
         sl = class_765.method_24187(light);
      }

      float ao;
      if (lu == 0) {
         ao = state.method_26210(this.region, pos);
      } else {
         ao = 1.0F;
      }

      boolean useAo = ao < 1.0F;
      bl = Math.max(bl, lu);
      int crs = (fo || fc) && lu == 0 && useAo ? 255 : 0;
      if (!fo && op) {
         class_265 shape = state.method_26218(this.region, pos);
         crs = ((VoxelShapeExtended)shape).getCornerOcclusion();
      }

      return packFC(fc) | packFO(fo) | packOP(op) | packEM(em) | packCO(crs) | packAO(ao) | packSL(sl) | packBL(bl);
   }

   public static int packBL(int blockLight) {
      return (blockLight & 15) << 0;
   }

   public static int unpackBL(int word) {
      return word >>> 0 & 15;
   }

   public static int packSL(int skyLight) {
      return (skyLight & 15) << 4;
   }

   public static int unpackSL(int word) {
      return word >>> 4 & 15;
   }

   public static int packAO(float ao) {
      int aoi = (int)(ao * 2048.0F);
      return (aoi & 4095) << 8;
   }

   public static float unpackAO(int word) {
      int aoi = word >>> 8 & 4095;
      return (float)aoi * 4.8828125E-4F;
   }

   public static int packCO(int co) {
      return (co & 255) << 20;
   }

   public static int unpackCO(int word) {
      return word >>> 20 & 255;
   }

   public static int packEM(boolean emissive) {
      return (emissive ? 1 : 0) << 28;
   }

   public static boolean unpackEM(int word) {
      return (word >>> 28 & 1) != 0;
   }

   public static int packOP(boolean opaque) {
      return (opaque ? 1 : 0) << 29;
   }

   public static boolean unpackOP(int word) {
      return (word >>> 29 & 1) != 0;
   }

   public static int packFO(boolean opaque) {
      return (opaque ? 1 : 0) << 30;
   }

   public static boolean unpackFO(int word) {
      return (word >>> 30 & 1) != 0;
   }

   public static int packFC(boolean fullCube) {
      return (fullCube ? 1 : 0) << 31;
   }

   public static boolean unpackFC(int word) {
      return (word >>> 31 & 1) != 0;
   }

   public static int getLightmap(int word) {
      return class_765.method_23687(unpackBL(word), unpackSL(word));
   }

   public static int getEmissiveLightmap(int word) {
      return unpackEM(word) ? 15728880 : getLightmap(word);
   }

   public class_1920 getRegion() {
      return this.region;
   }
}
