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

import net.minecraft.world.entity.LivingEntity;
import java.util.Optional;
import net.minecraft.world.level.block.Block;
import net.minecraft.tags.Tag;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.ai.memory.WalkTarget;
import net.minecraft.server.level.ServerLevel;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Mob;

public class JumpOnBed extends Behavior<Mob> {
    private final float speedModifier;
    @Nullable
    private BlockPos targetBed;
    private int remainingTimeToReachBed;
    private int remainingJumps;
    private int remainingCooldownUntilNextJump;
    
    public JumpOnBed(final float float1) {
        super(ImmutableMap.<MemoryModuleType<BlockPos>, MemoryStatus>of(MemoryModuleType.NEAREST_BED, MemoryStatus.VALUE_PRESENT, (MemoryModuleType<BlockPos>)MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT));
        this.speedModifier = float1;
    }
    
    @Override
    protected boolean checkExtraStartConditions(final ServerLevel zd, final Mob aoz) {
        return aoz.isBaby() && this.nearBed(zd, aoz);
    }
    
    @Override
    protected void start(final ServerLevel zd, final Mob aoz, final long long3) {
        super.start(zd, aoz, long3);
        this.getNearestBed(aoz).ifPresent(fu -> {
            this.targetBed = fu;
            this.remainingTimeToReachBed = 100;
            this.remainingJumps = 3 + zd.random.nextInt(4);
            this.remainingCooldownUntilNextJump = 0;
            this.startWalkingTowardsBed(aoz, fu);
        });
    }
    
    @Override
    protected void stop(final ServerLevel zd, final Mob aoz, final long long3) {
        super.stop(zd, aoz, long3);
        this.targetBed = null;
        this.remainingTimeToReachBed = 0;
        this.remainingJumps = 0;
        this.remainingCooldownUntilNextJump = 0;
    }
    
    @Override
    protected boolean canStillUse(final ServerLevel zd, final Mob aoz, final long long3) {
        return aoz.isBaby() && this.targetBed != null && this.isBed(zd, this.targetBed) && !this.tiredOfWalking(zd, aoz) && !this.tiredOfJumping(zd, aoz);
    }
    
    @Override
    protected boolean timedOut(final long long1) {
        return false;
    }
    
    @Override
    protected void tick(final ServerLevel zd, final Mob aoz, final long long3) {
        if (!this.onOrOverBed(zd, aoz)) {
            --this.remainingTimeToReachBed;
            return;
        }
        if (this.remainingCooldownUntilNextJump > 0) {
            --this.remainingCooldownUntilNextJump;
            return;
        }
        if (this.onBedSurface(zd, aoz)) {
            aoz.getJumpControl().jump();
            --this.remainingJumps;
            this.remainingCooldownUntilNextJump = 5;
        }
    }
    
    private void startWalkingTowardsBed(final Mob aoz, final BlockPos fu) {
        aoz.getBrain().<WalkTarget>setMemory(MemoryModuleType.WALK_TARGET, new WalkTarget(fu, this.speedModifier, 0));
    }
    
    private boolean nearBed(final ServerLevel zd, final Mob aoz) {
        return this.onOrOverBed(zd, aoz) || this.getNearestBed(aoz).isPresent();
    }
    
    private boolean onOrOverBed(final ServerLevel zd, final Mob aoz) {
        final BlockPos fu4 = aoz.blockPosition();
        final BlockPos fu5 = fu4.below();
        return this.isBed(zd, fu4) || this.isBed(zd, fu5);
    }
    
    private boolean onBedSurface(final ServerLevel zd, final Mob aoz) {
        return this.isBed(zd, aoz.blockPosition());
    }
    
    private boolean isBed(final ServerLevel zd, final BlockPos fu) {
        return zd.getBlockState(fu).is(BlockTags.BEDS);
    }
    
    private Optional<BlockPos> getNearestBed(final Mob aoz) {
        return aoz.getBrain().<BlockPos>getMemory(MemoryModuleType.NEAREST_BED);
    }
    
    private boolean tiredOfWalking(final ServerLevel zd, final Mob aoz) {
        return !this.onOrOverBed(zd, aoz) && this.remainingTimeToReachBed <= 0;
    }
    
    private boolean tiredOfJumping(final ServerLevel zd, final Mob aoz) {
        return this.onOrOverBed(zd, aoz) && this.remainingJumps <= 0;
    }
}
