package me.km.utils;

import com.google.common.collect.Sets;
import java.util.Set;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.Explosion;
import net.minecraft.world.World;

public class ExplosionUtils {
    public static void explosion(Explosion ex, World w) {
        ex.getAffectedBlockPositions().clear();

        ReflectionUtils.setNoBreakMode(ex);
        Vec3d pos = ex.getPosition();

        Entity exploder = ReflectionUtils.getExploder(ex);
        float size = ReflectionUtils.getSize(ex);

        ex.getAffectedBlockPositions().addAll(getAffectedBlocks(ex, w, size, pos.x, pos.y, pos.z, exploder));
    }

    private static Set<BlockPos> getAffectedBlocks(Explosion ex, World w, float size, double x, double y, double z, Entity exploder) {
        Set<BlockPos> set = Sets.newHashSet();
        for(int j = 0; j < 16; ++j) {
            for(int k = 0; k < 16; ++k) {
                for(int l = 0; l < 16; ++l) {
                    if(j == 0 || j == 15 || k == 0 || k == 15 || l == 0 || l == 15) {
                        // calc direction vector
                        double dirX = j / 7.5 - 1.0;
                        double dirY = k / 7.5 - 1.0;
                        double dirZ = l / 7.5 - 1.0;
                        double dirLength = Math.sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
                        dirX /= dirLength;
                        dirY /= dirLength;
                        dirZ /= dirLength;
                        // scale to the right size, moved outside of the loop
                        dirX *= 0.3;
                        dirY *= 0.3;
                        dirZ *= 0.3;

                        float strength = size * (0.7f + w.rand.nextFloat() * 0.6f);
                        double currentX = x;
                        double currentY = y;
                        double currentZ = z;

                        for(; strength > 0.0f; strength -= 0.225f) {
                            BlockPos pos = new BlockPos(currentX, currentY, currentZ);
                            BlockState state = w.getBlockState(pos);
                            IFluidState fState = w.getFluidState(pos);
                            if(!state.isAir(w, pos) || !fState.isEmpty()) {
                                float resistance = Math.max(state.getExplosionResistance(w, pos, exploder, ex), fState.getExplosionResistance(w, pos, exploder, ex));
                                if(exploder != null) {
                                    resistance = exploder.getExplosionResistance(ex, w, pos, state, fState, resistance);
                                }

                                // make explosives stronger, keep strong resistance but lower low resistance
                                if(resistance <= 10) {
                                    resistance = Math.min(resistance, 1.0f);
                                }

                                strength -= (resistance + 0.3F) * 0.3F;
                            }

                            if(strength > 0.0F && (exploder == null || exploder.canExplosionDestroyBlock(ex, w, pos, state, strength))) {
                                set.add(pos);
                            }

                            currentX += dirX;
                            currentY += dirY;
                            currentZ += dirZ;
                        }
                    }
                }
            }
        }
        return set;
    }
}
