package net.minecraft.world.level.pathfinder;

import javax.annotation.Nullable;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.tags.Tag;
import net.minecraft.tags.FluidTags;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;

public class SwimNodeEvaluator extends NodeEvaluator {
    private final boolean allowBreaching;
    
    public SwimNodeEvaluator(final boolean boolean1) {
        this.allowBreaching = boolean1;
    }
    
    @Override
    public Node getStart() {
        return super.getNode(Mth.floor(this.mob.getBoundingBox().minX), Mth.floor(this.mob.getBoundingBox().minY + 0.5), Mth.floor(this.mob.getBoundingBox().minZ));
    }
    
    @Override
    public Target getGoal(final double double1, final double double2, final double double3) {
        return new Target(super.getNode(Mth.floor(double1 - this.mob.getBbWidth() / 2.0f), Mth.floor(double2 + 0.5), Mth.floor(double3 - this.mob.getBbWidth() / 2.0f)));
    }
    
    @Override
    public int getNeighbors(final Node[] arr, final Node czd) {
        int integer4 = 0;
        for (final Direction fz8 : Direction.values()) {
            final Node czd2 = this.getWaterNode(czd.x + fz8.getStepX(), czd.y + fz8.getStepY(), czd.z + fz8.getStepZ());
            if (czd2 != null && !czd2.closed) {
                arr[integer4++] = czd2;
            }
        }
        return integer4;
    }
    
    @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) {
        return this.getBlockPathType(bpg, integer2, integer3, integer4);
    }
    
    @Override
    public BlockPathTypes getBlockPathType(final BlockGetter bpg, final int integer2, final int integer3, final int integer4) {
        final BlockPos fu6 = new BlockPos(integer2, integer3, integer4);
        final FluidState cxa7 = bpg.getFluidState(fu6);
        final BlockState cfj8 = bpg.getBlockState(fu6);
        if (cxa7.isEmpty() && cfj8.isPathfindable(bpg, fu6.below(), PathComputationType.WATER) && cfj8.isAir()) {
            return BlockPathTypes.BREACH;
        }
        if (!cxa7.is(FluidTags.WATER) || !cfj8.isPathfindable(bpg, fu6, PathComputationType.WATER)) {
            return BlockPathTypes.BLOCKED;
        }
        return BlockPathTypes.WATER;
    }
    
    @Nullable
    private Node getWaterNode(final int integer1, final int integer2, final int integer3) {
        final BlockPathTypes czb5 = this.isFree(integer1, integer2, integer3);
        if ((this.allowBreaching && czb5 == BlockPathTypes.BREACH) || czb5 == BlockPathTypes.WATER) {
            return this.getNode(integer1, integer2, integer3);
        }
        return null;
    }
    
    @Nullable
    @Override
    protected Node getNode(final int integer1, final int integer2, final int integer3) {
        Node czd5 = null;
        final BlockPathTypes czb6 = this.getBlockPathType(this.mob.level, 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 (this.level.getFluidState(new BlockPos(integer1, integer2, integer3)).isEmpty()) {
                final Node node = czd5;
                node.costMalus += 8.0f;
            }
        }
        if (czb6 == BlockPathTypes.OPEN) {
            return czd5;
        }
        return czd5;
    }
    
    private BlockPathTypes isFree(final int integer1, final int integer2, final int integer3) {
        final BlockPos.MutableBlockPos a5 = new BlockPos.MutableBlockPos();
        for (int integer4 = integer1; integer4 < integer1 + this.entityWidth; ++integer4) {
            for (int integer5 = integer2; integer5 < integer2 + this.entityHeight; ++integer5) {
                for (int integer6 = integer3; integer6 < integer3 + this.entityDepth; ++integer6) {
                    final FluidState cxa9 = this.level.getFluidState(a5.set(integer4, integer5, integer6));
                    final BlockState cfj10 = this.level.getBlockState(a5.set(integer4, integer5, integer6));
                    if (cxa9.isEmpty() && cfj10.isPathfindable(this.level, a5.below(), PathComputationType.WATER) && cfj10.isAir()) {
                        return BlockPathTypes.BREACH;
                    }
                    if (!cxa9.is(FluidTags.WATER)) {
                        return BlockPathTypes.BLOCKED;
                    }
                }
            }
        }
        final BlockState cfj11 = this.level.getBlockState(a5);
        if (cfj11.isPathfindable(this.level, a5, PathComputationType.WATER)) {
            return BlockPathTypes.WATER;
        }
        return BlockPathTypes.BLOCKED;
    }
}
