package dev.crucifixbeta.mod.modules.impl.render;

import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.AmbientOcclusionEvent;
import dev.crucifixbeta.api.events.impl.ChunkOcclusionEvent;
import dev.crucifixbeta.api.events.impl.RenderBlockEntityEvent;
import dev.crucifixbeta.mod.gui.windows.WindowsScreen;
import dev.crucifixbeta.mod.gui.windows.impl.ItemSelectWindow;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.settings.impl.BooleanSetting;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.BlockPos.Mutable;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;

@Environment(EnvType.CLIENT)
public class Xray extends Module {
   public static Xray INSTANCE;
   public final BooleanSetting edit = this.add(new BooleanSetting("Edit", false).injectTask(this::openGui));
   private static final ThreadLocal<Mutable> EXPOSED_POS;

   public Xray() {
      super("Xray", Module.Category.Render);
      this.setChinese("\u77ff\u7269\u900f\u89c6");
      INSTANCE = this;
   }

   private void openGui() {
      this.edit.setValueWithoutTask(false);
      if (!nullCheck()) {
         mc.setScreen(new WindowsScreen(new ItemSelectWindow(CrucifixBeta.XRAY)));
      }
   }

   @Override
   public void onEnable() {
      if (!nullCheck()) {
         mc.worldRenderer.reload();
      }
   }

   @Override
   public void onDisable() {
      mc.worldRenderer.reload();
   }

   public boolean isBlocked(Block block) {
      return !CrucifixBeta.XRAY.inWhitelist(block.getTranslationKey());
   }

   @EventListener
   private void onRenderBlockEntity(RenderBlockEntityEvent event) {
      if (this.isBlocked(event.blockEntity.getCachedState().getBlock())) {
         event.cancel();
      }
   }

   @EventListener
   private void onChunkOcclusion(ChunkOcclusionEvent event) {
      event.cancel();
   }

   @EventListener
   private void onAmbientOcclusion(AmbientOcclusionEvent event) {
      event.lightLevel = 1.0F;
   }

   public static boolean shouldBlock(BlockState state) {
      return INSTANCE.isOn() && INSTANCE.isBlocked(state.getBlock());
   }

   public boolean modifyDrawSide(BlockState state, BlockView view, BlockPos pos, Direction facing, boolean returns) {
      if (!returns && !this.isBlocked(state.getBlock())) {
         BlockPos var6 = pos.offset(facing);
         BlockState var7 = view.getBlockState(var6);
         return var7.getCullingFace(view, var6, facing.getOpposite()) != VoxelShapes.fullCube() || var7.getBlock() != state.getBlock() || isExposed(var6);
      } else {
         return returns;
      }
   }

   public static boolean isExposed(BlockPos blockPos) {
      for (Direction var4 : Direction.values()) {
         if (!mc.world.getBlockState(EXPOSED_POS.get().set(blockPos, var4)).isOpaque()) {
            return true;
         }
      }

      return false;
   }

   static {

      EXPOSED_POS = ThreadLocal.withInitial(Mutable::new);
   }
}
