package net.minecraft.world.entity.ai.goal;

import java.util.Iterator;
import java.util.Objects;
import net.minecraft.core.Position;
import net.minecraft.world.level.pathfinder.Node;
import java.util.Optional;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.core.Vec3i;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
import net.minecraft.world.entity.ai.util.RandomPos;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.entity.ai.village.poi.PoiType;
import net.minecraft.server.level.ServerLevel;
import java.util.EnumSet;
import com.google.common.collect.Lists;
import java.util.function.BooleanSupplier;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.entity.PathfinderMob;

public class MoveThroughVillageGoal extends Goal {
    protected final PathfinderMob mob;
    private final double speedModifier;
    private Path path;
    private BlockPos poiPos;
    private final boolean onlyAtNight;
    private final List<BlockPos> visited;
    private final int distanceToPoi;
    private final BooleanSupplier canDealWithDoors;
    
    public MoveThroughVillageGoal(final PathfinderMob apg, final double double2, final boolean boolean3, final int integer, final BooleanSupplier booleanSupplier) {
        this.visited = Lists.newArrayList();
        this.mob = apg;
        this.speedModifier = double2;
        this.onlyAtNight = boolean3;
        this.distanceToPoi = integer;
        this.canDealWithDoors = booleanSupplier;
        this.setFlags(EnumSet.<Flag>of(Flag.MOVE));
        if (!this.hasGroundPathNavigation()) {
            throw new IllegalArgumentException("Unsupported mob for MoveThroughVillageGoal");
        }
    }
    
    @Override
    public boolean canUse() {
        if (!this.hasGroundPathNavigation()) {
            return false;
        }
        this.updateVisited();
        if (this.onlyAtNight && this.mob.level.isDay()) {
            return false;
        }
        final ServerLevel zd2 = (ServerLevel)this.mob.level;
        final BlockPos fu4 = this.mob.blockPosition();
        if (!zd2.isCloseToVillage(fu4, 6)) {
            return false;
        }
        final ServerLevel serverLevel;
        Optional<BlockPos> optional5;
        final Vec3i gr;
        final Vec3 dem4 = RandomPos.getLandPos(this.mob, 15, 7, fu3 -> {
            if (!serverLevel.isVillage(fu3)) {
                return Double.NEGATIVE_INFINITY;
            }
            else {
                optional5 = serverLevel.getPoiManager().find(PoiType.ALL, this::hasNotVisited, fu3, 10, PoiManager.Occupancy.IS_OCCUPIED);
                if (!optional5.isPresent()) {
                    return Double.NEGATIVE_INFINITY;
                }
                else {
                    return -optional5.get().distSqr(gr);
                }
            }
        });
        if (dem4 == null) {
            return false;
        }
        final Optional<BlockPos> optional6 = zd2.getPoiManager().find(PoiType.ALL, this::hasNotVisited, new BlockPos(dem4), 10, PoiManager.Occupancy.IS_OCCUPIED);
        if (!optional6.isPresent()) {
            return false;
        }
        this.poiPos = optional6.get().immutable();
        final GroundPathNavigation awu6 = (GroundPathNavigation)this.mob.getNavigation();
        final boolean boolean7 = awu6.canOpenDoors();
        awu6.setCanOpenDoors(this.canDealWithDoors.getAsBoolean());
        this.path = awu6.createPath(this.poiPos, 0);
        awu6.setCanOpenDoors(boolean7);
        if (this.path == null) {
            final Vec3 dem5 = RandomPos.getPosTowards(this.mob, 10, 7, Vec3.atBottomCenterOf(this.poiPos));
            if (dem5 == null) {
                return false;
            }
            awu6.setCanOpenDoors(this.canDealWithDoors.getAsBoolean());
            this.path = this.mob.getNavigation().createPath(dem5.x, dem5.y, dem5.z, 0);
            awu6.setCanOpenDoors(boolean7);
            if (this.path == null) {
                return false;
            }
        }
        for (int integer8 = 0; integer8 < this.path.getSize(); ++integer8) {
            final Node czd9 = this.path.get(integer8);
            final BlockPos fu5 = new BlockPos(czd9.x, czd9.y + 1, czd9.z);
            if (DoorBlock.isWoodenDoor(this.mob.level, fu5)) {
                this.path = this.mob.getNavigation().createPath(czd9.x, czd9.y, czd9.z, 0);
                break;
            }
        }
        return this.path != null;
    }
    
    @Override
    public boolean canContinueToUse() {
        return !this.mob.getNavigation().isDone() && !this.poiPos.closerThan(this.mob.position(), this.mob.getBbWidth() + this.distanceToPoi);
    }
    
    @Override
    public void start() {
        this.mob.getNavigation().moveTo(this.path, this.speedModifier);
    }
    
    @Override
    public void stop() {
        if (this.mob.getNavigation().isDone() || this.poiPos.closerThan(this.mob.position(), this.distanceToPoi)) {
            this.visited.add(this.poiPos);
        }
    }
    
    private boolean hasNotVisited(final BlockPos fu) {
        for (final BlockPos fu2 : this.visited) {
            if (Objects.equals(fu, fu2)) {
                return false;
            }
        }
        return true;
    }
    
    private void updateVisited() {
        if (this.visited.size() > 15) {
            this.visited.remove(0);
        }
    }
    
    private boolean hasGroundPathNavigation() {
        return this.mob.getNavigation() instanceof GroundPathNavigation;
    }
}
