package net.minecraft.world.level.pathfinder;

import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.tags.Tag;
import net.minecraft.tags.BlockTags;
import java.util.EnumSet;
import net.minecraft.world.level.BlockGetter;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.Set;
import net.minecraft.world.level.block.Block;
import com.google.common.collect.Sets;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.level.PathNavigationRegion;

public class FlyNodeEvaluator extends WalkNodeEvaluator {
    @Override
    public void prepare(final PathNavigationRegion bql, final Mob aoz) {
        super.prepare(bql, aoz);
        this.oldWaterCost = aoz.getPathfindingMalus(BlockPathTypes.WATER);
    }
    
    @Override
    public void done() {
        this.mob.setPathfindingMalus(BlockPathTypes.WATER, this.oldWaterCost);
        super.done();
    }
    
    @Override
    public Node getStart() {
        int integer2;
        if (this.canFloat() && this.mob.isInWater()) {
            integer2 = Mth.floor(this.mob.getY());
            final BlockPos.MutableBlockPos a3 = new BlockPos.MutableBlockPos(this.mob.getX(), integer2, this.mob.getZ());
            for (Block bvr4 = this.level.getBlockState(a3).getBlock(); bvr4 == Blocks.WATER; bvr4 = this.level.getBlockState(a3).getBlock()) {
                ++integer2;
                a3.set(this.mob.getX(), integer2, this.mob.getZ());
            }
        }
        else {
            integer2 = Mth.floor(this.mob.getY() + 0.5);
        }
        final BlockPos fu3 = this.mob.blockPosition();
        final BlockPathTypes czb4 = this.getBlockPathType(this.mob, fu3.getX(), integer2, fu3.getZ());
        if (this.mob.getPathfindingMalus(czb4) < 0.0f) {
            final Set<BlockPos> set5 = Sets.newHashSet();
            set5.add(new BlockPos(this.mob.getBoundingBox().minX, integer2, this.mob.getBoundingBox().minZ));
            set5.add(new BlockPos(this.mob.getBoundingBox().minX, integer2, this.mob.getBoundingBox().maxZ));
            set5.add(new BlockPos(this.mob.getBoundingBox().maxX, integer2, this.mob.getBoundingBox().minZ));
            set5.add(new BlockPos(this.mob.getBoundingBox().maxX, integer2, this.mob.getBoundingBox().maxZ));
            for (final BlockPos fu4 : set5) {
                final BlockPathTypes czb5 = this.getBlockPathType(this.mob, fu4);
                if (this.mob.getPathfindingMalus(czb5) >= 0.0f) {
                    return super.getNode(fu4.getX(), fu4.getY(), fu4.getZ());
                }
            }
        }
        return super.getNode(fu3.getX(), integer2, fu3.getZ());
    }
    
    @Override
    public Target getGoal(final double double1, final double double2, final double double3) {
        return new Target(super.getNode(Mth.floor(double1), Mth.floor(double2), Mth.floor(double3)));
    }
    
    @Override
    public int getNeighbors(final Node[] arr, final Node czd) {
        int integer4 = 0;
        final Node czd2 = this.getNode(czd.x, czd.y, czd.z + 1);
        if (this.isOpen(czd2)) {
            arr[integer4++] = czd2;
        }
        final Node czd3 = this.getNode(czd.x - 1, czd.y, czd.z);
        if (this.isOpen(czd3)) {
            arr[integer4++] = czd3;
        }
        final Node czd4 = this.getNode(czd.x + 1, czd.y, czd.z);
        if (this.isOpen(czd4)) {
            arr[integer4++] = czd4;
        }
        final Node czd5 = this.getNode(czd.x, czd.y, czd.z - 1);
        if (this.isOpen(czd5)) {
            arr[integer4++] = czd5;
        }
        final Node czd6 = this.getNode(czd.x, czd.y + 1, czd.z);
        if (this.isOpen(czd6)) {
            arr[integer4++] = czd6;
        }
        final Node czd7 = this.getNode(czd.x, czd.y - 1, czd.z);
        if (this.isOpen(czd7)) {
            arr[integer4++] = czd7;
        }
        final Node czd8 = this.getNode(czd.x, czd.y + 1, czd.z + 1);
        if (this.isOpen(czd8) && this.hasMalus(czd2) && this.hasMalus(czd6)) {
            arr[integer4++] = czd8;
        }
        final Node czd9 = this.getNode(czd.x - 1, czd.y + 1, czd.z);
        if (this.isOpen(czd9) && this.hasMalus(czd3) && this.hasMalus(czd6)) {
            arr[integer4++] = czd9;
        }
        final Node czd10 = this.getNode(czd.x + 1, czd.y + 1, czd.z);
        if (this.isOpen(czd10) && this.hasMalus(czd4) && this.hasMalus(czd6)) {
            arr[integer4++] = czd10;
        }
        final Node czd11 = this.getNode(czd.x, czd.y + 1, czd.z - 1);
        if (this.isOpen(czd11) && this.hasMalus(czd5) && this.hasMalus(czd6)) {
            arr[integer4++] = czd11;
        }
        final Node czd12 = this.getNode(czd.x, czd.y - 1, czd.z + 1);
        if (this.isOpen(czd12) && this.hasMalus(czd2) && this.hasMalus(czd7)) {
            arr[integer4++] = czd12;
        }
        final Node czd13 = this.getNode(czd.x - 1, czd.y - 1, czd.z);
        if (this.isOpen(czd13) && this.hasMalus(czd3) && this.hasMalus(czd7)) {
            arr[integer4++] = czd13;
        }
        final Node czd14 = this.getNode(czd.x + 1, czd.y - 1, czd.z);
        if (this.isOpen(czd14) && this.hasMalus(czd4) && this.hasMalus(czd7)) {
            arr[integer4++] = czd14;
        }
        final Node czd15 = this.getNode(czd.x, czd.y - 1, czd.z - 1);
        if (this.isOpen(czd15) && this.hasMalus(czd5) && this.hasMalus(czd7)) {
            arr[integer4++] = czd15;
        }
        final Node czd16 = this.getNode(czd.x + 1, czd.y, czd.z - 1);
        if (this.isOpen(czd16) && this.hasMalus(czd5) && this.hasMalus(czd4)) {
            arr[integer4++] = czd16;
        }
        final Node czd17 = this.getNode(czd.x + 1, czd.y, czd.z + 1);
        if (this.isOpen(czd17) && this.hasMalus(czd2) && this.hasMalus(czd4)) {
            arr[integer4++] = czd17;
        }
        final Node czd18 = this.getNode(czd.x - 1, czd.y, czd.z - 1);
        if (this.isOpen(czd18) && this.hasMalus(czd5) && this.hasMalus(czd3)) {
            arr[integer4++] = czd18;
        }
        final Node czd19 = this.getNode(czd.x - 1, czd.y, czd.z + 1);
        if (this.isOpen(czd19) && this.hasMalus(czd2) && this.hasMalus(czd3)) {
            arr[integer4++] = czd19;
        }
        final Node czd20 = this.getNode(czd.x + 1, czd.y + 1, czd.z - 1);
        if (this.isOpen(czd20) && this.hasMalus(czd16) && this.hasMalus(czd5) && this.hasMalus(czd4) && this.hasMalus(czd6) && this.hasMalus(czd11) && this.hasMalus(czd10)) {
            arr[integer4++] = czd20;
        }
        final Node czd21 = this.getNode(czd.x + 1, czd.y + 1, czd.z + 1);
        if (this.isOpen(czd21) && this.hasMalus(czd17) && this.hasMalus(czd2) && this.hasMalus(czd4) && this.hasMalus(czd6) && this.hasMalus(czd8) && this.hasMalus(czd10)) {
            arr[integer4++] = czd21;
        }
        final Node czd22 = this.getNode(czd.x - 1, czd.y + 1, czd.z - 1);
        if (this.isOpen(czd22) && this.hasMalus(czd18) && this.hasMalus(czd5) && (this.hasMalus(czd3) & this.hasMalus(czd6)) && this.hasMalus(czd11) && this.hasMalus(czd9)) {
            arr[integer4++] = czd22;
        }
        final Node czd23 = this.getNode(czd.x - 1, czd.y + 1, czd.z + 1);
        if (this.isOpen(czd23) && this.hasMalus(czd19) && this.hasMalus(czd2) && (this.hasMalus(czd3) & this.hasMalus(czd6)) && this.hasMalus(czd8) && this.hasMalus(czd9)) {
            arr[integer4++] = czd23;
        }
        final Node czd24 = this.getNode(czd.x + 1, czd.y - 1, czd.z - 1);
        if (this.isOpen(czd24) && this.hasMalus(czd16) && this.hasMalus(czd5) && this.hasMalus(czd4) && this.hasMalus(czd7) && this.hasMalus(czd15) && this.hasMalus(czd14)) {
            arr[integer4++] = czd24;
        }
        final Node czd25 = this.getNode(czd.x + 1, czd.y - 1, czd.z + 1);
        if (this.isOpen(czd25) && this.hasMalus(czd17) && this.hasMalus(czd2) && this.hasMalus(czd4) && this.hasMalus(czd7) && this.hasMalus(czd12) && this.hasMalus(czd14)) {
            arr[integer4++] = czd25;
        }
        final Node czd26 = this.getNode(czd.x - 1, czd.y - 1, czd.z - 1);
        if (this.isOpen(czd26) && this.hasMalus(czd18) && this.hasMalus(czd5) && this.hasMalus(czd3) && this.hasMalus(czd7) && this.hasMalus(czd15) && this.hasMalus(czd13)) {
            arr[integer4++] = czd26;
        }
        final Node czd27 = this.getNode(czd.x - 1, czd.y - 1, czd.z + 1);
        if (this.isOpen(czd27) && this.hasMalus(czd19) && this.hasMalus(czd2) && this.hasMalus(czd3) && this.hasMalus(czd7) && this.hasMalus(czd12) && this.hasMalus(czd13)) {
            arr[integer4++] = czd27;
        }
        return integer4;
    }
    
    private boolean hasMalus(@Nullable final Node czd) {
        return czd != null && czd.costMalus >= 0.0f;
    }
    
    private boolean isOpen(@Nullable final Node czd) {
        return czd != null && !czd.closed;
    }
    
    @Nullable
    @Override
    protected Node getNode(final int integer1, final int integer2, final int integer3) {
        Node czd5 = null;
        final BlockPathTypes czb6 = this.getBlockPathType(this.mob, integer1, integer2, integer3);
        final float float7 = this.mob.getPathfindingMalus(czb6);
        if (float7 >= 0.0f) {
            czd5 = super.getNode(integer1, integer2, integer3);
            czd5.type = czb6;
            czd5.costMalus = Math.max(czd5.costMalus, float7);
            if (czb6 == BlockPathTypes.WALKABLE) {
                final Node node = czd5;
                ++node.costMalus;
            }
        }
        if (czb6 == BlockPathTypes.OPEN || czb6 == BlockPathTypes.WALKABLE) {
            return czd5;
        }
        return czd5;
    }
    
    @Override
    public BlockPathTypes getBlockPathType(final BlockGetter bpg, final int integer2, final int integer3, final int integer4, final Mob aoz, final int integer6, final int integer7, final int integer8, final boolean boolean9, final boolean boolean10) {
        final EnumSet<BlockPathTypes> enumSet12 = EnumSet.<BlockPathTypes>noneOf(BlockPathTypes.class);
        BlockPathTypes czb13 = BlockPathTypes.BLOCKED;
        final BlockPos fu14 = aoz.blockPosition();
        czb13 = this.getBlockPathTypes(bpg, integer2, integer3, integer4, integer6, integer7, integer8, boolean9, boolean10, enumSet12, czb13, fu14);
        if (enumSet12.contains(BlockPathTypes.FENCE)) {
            return BlockPathTypes.FENCE;
        }
        BlockPathTypes czb14 = BlockPathTypes.BLOCKED;
        for (final BlockPathTypes czb15 : enumSet12) {
            if (aoz.getPathfindingMalus(czb15) < 0.0f) {
                return czb15;
            }
            if (aoz.getPathfindingMalus(czb15) < aoz.getPathfindingMalus(czb14)) {
                continue;
            }
            czb14 = czb15;
        }
        if (czb13 == BlockPathTypes.OPEN && aoz.getPathfindingMalus(czb14) == 0.0f) {
            return BlockPathTypes.OPEN;
        }
        return czb14;
    }
    
    @Override
    public BlockPathTypes getBlockPathType(final BlockGetter bpg, final int integer2, final int integer3, final int integer4) {
        final BlockPos.MutableBlockPos a6 = new BlockPos.MutableBlockPos();
        BlockPathTypes czb7 = WalkNodeEvaluator.getBlockPathTypeRaw(bpg, a6.set(integer2, integer3, integer4));
        if (czb7 == BlockPathTypes.OPEN && integer3 >= 1) {
            final BlockState cfj8 = bpg.getBlockState(a6.set(integer2, integer3 - 1, integer4));
            final BlockPathTypes czb8 = WalkNodeEvaluator.getBlockPathTypeRaw(bpg, a6.set(integer2, integer3 - 1, integer4));
            if (czb8 == BlockPathTypes.DAMAGE_FIRE || cfj8.is(Blocks.MAGMA_BLOCK) || czb8 == BlockPathTypes.LAVA || cfj8.is(BlockTags.CAMPFIRES)) {
                czb7 = BlockPathTypes.DAMAGE_FIRE;
            }
            else if (czb8 == BlockPathTypes.DAMAGE_CACTUS) {
                czb7 = BlockPathTypes.DAMAGE_CACTUS;
            }
            else if (czb8 == BlockPathTypes.DAMAGE_OTHER) {
                czb7 = BlockPathTypes.DAMAGE_OTHER;
            }
            else if (czb8 == BlockPathTypes.COCOA) {
                czb7 = BlockPathTypes.COCOA;
            }
            else if (czb8 == BlockPathTypes.FENCE) {
                czb7 = BlockPathTypes.FENCE;
            }
            else {
                czb7 = ((czb8 == BlockPathTypes.WALKABLE || czb8 == BlockPathTypes.OPEN || czb8 == BlockPathTypes.WATER) ? BlockPathTypes.OPEN : BlockPathTypes.WALKABLE);
            }
        }
        if (czb7 == BlockPathTypes.WALKABLE || czb7 == BlockPathTypes.OPEN) {
            czb7 = WalkNodeEvaluator.checkNeighbourBlocks(bpg, a6.set(integer2, integer3, integer4), czb7);
        }
        return czb7;
    }
    
    private BlockPathTypes getBlockPathType(final Mob aoz, final BlockPos fu) {
        return this.getBlockPathType(aoz, fu.getX(), fu.getY(), fu.getZ());
    }
    
    private BlockPathTypes getBlockPathType(final Mob aoz, final int integer2, final int integer3, final int integer4) {
        return this.getBlockPathType(this.level, integer2, integer3, integer4, aoz, this.entityWidth, this.entityHeight, this.entityDepth, this.canOpenDoors(), this.canPassDoors());
    }
}
