package dev.crucifixbeta.api.utils.combat.crystal;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Blocks;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public final class AsyncCrystalManager {
   public AsyncCrystalResult scan(CrystalWorldSnapshot snapshot, AsyncCrystalConfig config) {
      if (snapshot != null && snapshot.localPlayer() != null) {
         List var3 = this.targets(snapshot, config);
         if (var3.isEmpty()) {
            return AsyncCrystalResult.empty();
         } else {
            AsyncCrystalData var4 = this.scanCrystals(snapshot, config, var3);
            AsyncCrystalData var5 = this.scanPlacements(snapshot, config, var3);
            if (var4 == null || var5 != null && !(var4.targetDamage() >= var5.targetDamage())) {
               return var5 != null ? new AsyncCrystalResult(null, var5.targetDamage(), -1, var5.placePos(), var5.targetId()) : AsyncCrystalResult.empty();
            } else {
               return new AsyncCrystalResult(null, var4.targetDamage(), var4.crystalId(), null, var4.targetId());
            }
         }
      } else {
         return AsyncCrystalResult.empty();
      }
   }

   private List<CrystalEntitySnapshot> targets(CrystalWorldSnapshot snapshot, AsyncCrystalConfig config) {
      ArrayList<CrystalEntitySnapshot> var3 = new ArrayList<>();
      CrystalEntitySnapshot var4 = snapshot.localPlayer();
      double var5 = config.targetRange() * config.targetRange();

      for (CrystalEntitySnapshot var8 : snapshot.livingEntities()) {
         if (var8.id() != var4.id() && var8.type() == EntityType.PLAYER && var8.alive() && !(var8.pos().squaredDistanceTo(var4.pos()) > var5)) {
            var3.add(var8);
         }
      }

      var3.sort(Comparator.comparingDouble(e -> e.pos().squaredDistanceTo(var4.pos())));
      return var3;
   }

   private AsyncCrystalData scanCrystals(CrystalWorldSnapshot snapshot, AsyncCrystalConfig config, List<CrystalEntitySnapshot> targets) {
      AsyncCrystalData var4 = null;

      for (CrystalEntitySnapshot var6 : snapshot.crystals()) {
         if (var6.alive() && var6.age() >= config.minAge() && !(snapshot.eyePos().squaredDistanceTo(var6.pos()) > config.breakRange() * config.breakRange())) {
            float var7 = snapshot.explosionDamage(var6.pos(), snapshot.localPlayer(), config.terrainIgnore());
            if (!this.selfDamageInvalid(var7, config)) {
               for (CrystalEntitySnapshot var9 : targets) {
                  if (!(var6.pos().squaredDistanceTo(var9.pos()) > 144.0)) {
                     float var10 = snapshot.explosionDamage(var6.pos(), var9, config.terrainIgnore());
                     if (this.damageValid(var10, var9, var7, config) && (var4 == null || var10 > var4.targetDamage())) {
                        var4 = AsyncCrystalData.breakCrystal(var6, var9.id(), var10, var7);
                     }
                  }
               }
            }
         }
      }

      return var4;
   }

   private AsyncCrystalData scanPlacements(CrystalWorldSnapshot snapshot, AsyncCrystalConfig config, List<CrystalEntitySnapshot> targets) {
      AsyncCrystalData var4 = null;
      int var5 = (int)Math.ceil(config.breakRange() + 1.5);
      BlockPos var6 = BlockPos.ofFloored(snapshot.eyePos());
      int var7 = var5 * var5;

      for (int var8 = -var5; var8 <= var5; var8++) {
         for (int var9 = -var5; var9 <= var5; var9++) {
            for (int var10 = -var5; var10 <= var5; var10++) {
               if (var8 * var8 + var9 * var9 + var10 * var10 <= var7) {
                  BlockPos var11 = var6.add(var8, var9, var10);
                  if (this.canPlaceCrystal(snapshot, var11, config)) {
                     Vec3d var12 = var11.toBottomCenterPos();
                     float var13 = snapshot.explosionDamage(var12, snapshot.localPlayer(), config.terrainIgnore());
                     if (!this.selfDamageInvalid(var13, config)) {
                        for (CrystalEntitySnapshot var15 : targets) {
                           if (!(var12.squaredDistanceTo(var15.pos()) > 144.0)) {
                              float var16 = snapshot.explosionDamage(var12, var15, config.terrainIgnore());
                              if (this.damageValid(var16, var15, var13, config) && (var4 == null || var16 > var4.targetDamage())) {
                                 var4 = AsyncCrystalData.place(var11, var12, var15.id(), var16, var13);
                              }
                           }
                        }
                     }
                  }
               }
            }
         }
      }

      return var4;
   }

   private boolean canPlaceCrystal(CrystalWorldSnapshot snapshot, BlockPos pos, AsyncCrystalConfig config) {
      BlockPos var4 = pos.down();
      if (snapshot.block(var4) != Blocks.BEDROCK && snapshot.block(var4) != Blocks.OBSIDIAN) {
         return false;
      } else if (!this.canTouch(snapshot, var4, config.placeRange())) {
         return false;
      } else {
         BlockPos var5 = var4.up();
         BlockPos var6 = var5.up();
         boolean var7 = snapshot.isAir(var5) || snapshot.hasCrystal(var5) && snapshot.block(var5) == Blocks.FIRE;
         return var7 && (!config.lowVersion() || snapshot.isAir(var6))
            ? !this.hasBlockingEntity(snapshot, var5, true, config.targetItems()) && !this.hasBlockingEntity(snapshot, var6, true, config.targetItems())
            : false;
      }
   }

   private boolean canTouch(CrystalWorldSnapshot snapshot, BlockPos pos, double range) {
      for (Direction var8 : Direction.values()) {
         Vec3d var9 = pos.toCenterPos()
            .add((double)var8.getVector().getX() * 0.5, (double)var8.getVector().getY() * 0.5, (double)var8.getVector().getZ() * 0.5);
         if (snapshot.eyePos().distanceTo(var9) <= range) {
            return true;
         }
      }

      return false;
   }

   private boolean hasBlockingEntity(CrystalWorldSnapshot snapshot, BlockPos pos, boolean ignoreCrystal, boolean ignoreItem) {
      for (CrystalEntitySnapshot var6 : snapshot.entities(new Box(pos))) {
         if (var6.alive() && (!ignoreItem || !var6.item()) && (!ignoreCrystal || !var6.endCrystal())) {
            return true;
         }
      }

      return false;
   }

   private boolean damageValid(float damage, CrystalEntitySnapshot target, float selfDamage, AsyncCrystalConfig config) {
      return !(damage <= 0.0F) && (!((double)damage < config.minDamage()) || !(damage < target.totalHealth()))
         ? !this.selfDamageInvalid(selfDamage, config)
         : false;
   }

   private boolean selfDamageInvalid(float selfDamage, AsyncCrystalConfig config) {
      return (double)selfDamage > config.maxSelf() || config.reserve() > 0.0 && (double)selfDamage > (double)config.playerHealth() - config.reserve();
   }
}
