package net.minecraft.world.entity.monster;

import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.MobType;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.ai.behavior.BehaviorUtils;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.EntitySelector;
import java.util.function.Predicate;
import net.minecraft.world.entity.LivingEntity;
import java.util.Optional;
import net.minecraft.world.entity.ai.behavior.StopAttackingIfTargetInvalid;
import net.minecraft.world.entity.ai.behavior.MeleeAttack;
import net.minecraft.world.entity.ai.behavior.SetWalkTargetFromAttackTargetIfTargetOutOfReach;
import java.util.List;
import net.minecraft.world.entity.ai.behavior.DoNothing;
import net.minecraft.world.entity.ai.behavior.SetWalkTargetFromLookTarget;
import com.mojang.datafixers.util.Pair;
import net.minecraft.world.entity.ai.behavior.RandomStroll;
import net.minecraft.util.IntRange;
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget;
import net.minecraft.world.entity.ai.behavior.Behavior;
import net.minecraft.world.entity.ai.behavior.MoveToTargetSink;
import net.minecraft.world.entity.ai.behavior.LookAtTargetSink;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import net.minecraft.world.entity.schedule.Activity;
import com.mojang.serialization.Dynamic;
import java.util.Collection;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.sensing.Sensor;
import net.minecraft.world.entity.ai.sensing.SensorType;
import com.google.common.collect.ImmutableList;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.monster.hoglin.HoglinBase;

public class Zoglin extends Monster implements Enemy, HoglinBase {
    private static final EntityDataAccessor<Boolean> DATA_BABY_ID;
    private int attackAnimationRemainingTicks;
    protected static final ImmutableList<? extends SensorType<? extends Sensor<? super Zoglin>>> SENSOR_TYPES;
    protected static final ImmutableList<? extends MemoryModuleType<?>> MEMORY_TYPES;
    
    public Zoglin(final EntityType<? extends Zoglin> aoq, final Level bqb) {
        super(aoq, bqb);
        this.xpReward = 5;
    }
    
    @Override
    protected Brain.Provider<Zoglin> brainProvider() {
        return Brain.<Zoglin>provider(Zoglin.MEMORY_TYPES, Zoglin.SENSOR_TYPES);
    }
    
    @Override
    protected Brain<?> makeBrain(final Dynamic<?> dynamic) {
        final Brain<Zoglin> apr3 = this.brainProvider().makeBrain(dynamic);
        initCoreActivity(apr3);
        initIdleActivity(apr3);
        initFightActivity(apr3);
        apr3.setCoreActivities(ImmutableSet.<Activity>of(Activity.CORE));
        apr3.setDefaultActivity(Activity.IDLE);
        apr3.useDefaultActivity();
        return apr3;
    }
    
    private static void initCoreActivity(final Brain<Zoglin> apr) {
        apr.addActivity(Activity.CORE, 0, ImmutableList.of(new LookAtTargetSink(45, 90), new MoveToTargetSink(200)));
    }
    
    private static void initIdleActivity(final Brain<Zoglin> apr) {
        apr.addActivity(Activity.IDLE, 10, ImmutableList.of(new Behavior(Zoglin::findNearestValidAttackTarget), new Behavior(new SetEntityLookTarget(8.0f), IntRange.of(30, 60)), new Behavior(ImmutableList.of(Pair.of(new RandomStroll(0.4f), 2), Pair.of(new SetWalkTargetFromLookTarget(0.4f, 3), 2), Pair.of(new DoNothing(30, 60), 1)))));
    }
    
    private static void initFightActivity(final Brain<Zoglin> apr) {
        apr.addActivityAndRemoveMemoryWhenStopped(Activity.FIGHT, 10, ImmutableList.of(new SetWalkTargetFromAttackTargetIfTargetOutOfReach(1.0f), new Behavior(Zoglin::isAdult, new MeleeAttack(40)), new Behavior(Zoglin::isBaby, new MeleeAttack(15)), new StopAttackingIfTargetInvalid()), MemoryModuleType.ATTACK_TARGET);
    }
    
    private Optional<? extends LivingEntity> findNearestValidAttackTarget() {
        return this.getBrain().<List<LivingEntity>>getMemory(MemoryModuleType.VISIBLE_LIVING_ENTITIES).orElse(ImmutableList.of()).stream().filter(Zoglin::isTargetable).findFirst();
    }
    
    private static boolean isTargetable(final LivingEntity aoy) {
        final EntityType<?> aoq2 = aoy.getType();
        return aoq2 != EntityType.ZOGLIN && aoq2 != EntityType.CREEPER && EntitySelector.ATTACK_ALLOWED.test(aoy);
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Boolean>define(Zoglin.DATA_BABY_ID, false);
    }
    
    @Override
    public void onSyncedDataUpdated(final EntityDataAccessor<?> tq) {
        super.onSyncedDataUpdated(tq);
        if (Zoglin.DATA_BABY_ID.equals(tq)) {
            this.refreshDimensions();
        }
    }
    
    public static AttributeSupplier.Builder createAttributes() {
        return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 40.0).add(Attributes.MOVEMENT_SPEED, 0.30000001192092896).add(Attributes.KNOCKBACK_RESISTANCE, 0.6000000238418579).add(Attributes.ATTACK_KNOCKBACK, 1.0).add(Attributes.ATTACK_DAMAGE, 6.0);
    }
    
    public boolean isAdult() {
        return !this.isBaby();
    }
    
    @Override
    public boolean doHurtTarget(final Entity aom) {
        if (!(aom instanceof LivingEntity)) {
            return false;
        }
        this.attackAnimationRemainingTicks = 10;
        this.level.broadcastEntityEvent(this, (byte)4);
        this.playSound(SoundEvents.ZOGLIN_ATTACK, 1.0f, this.getVoicePitch());
        return HoglinBase.hurtAndThrowTarget(this, (LivingEntity)aom);
    }
    
    @Override
    protected void blockedByShield(final LivingEntity aoy) {
        if (!this.isBaby()) {
            HoglinBase.throwTarget(this, aoy);
        }
    }
    
    @Override
    public boolean hurt(final DamageSource anw, final float float2) {
        final boolean boolean4 = super.hurt(anw, float2);
        if (this.level.isClientSide) {
            return false;
        }
        if (!boolean4 || !(anw.getEntity() instanceof LivingEntity)) {
            return boolean4;
        }
        final LivingEntity aoy5 = (LivingEntity)anw.getEntity();
        if (EntitySelector.ATTACK_ALLOWED.test(aoy5) && !BehaviorUtils.isOtherTargetMuchFurtherAwayThanCurrentAttackTarget(this, aoy5, 4.0)) {
            this.setAttackTarget(aoy5);
        }
        return boolean4;
    }
    
    private void setAttackTarget(final LivingEntity aoy) {
        this.brain.<Long>eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE);
        this.brain.<LivingEntity>setMemoryWithExpiry(MemoryModuleType.ATTACK_TARGET, aoy, 200L);
    }
    
    @Override
    public Brain<Zoglin> getBrain() {
        return (Brain<Zoglin>)super.getBrain();
    }
    
    protected void updateActivity() {
        final Activity bfl2 = this.brain.getActiveNonCoreActivity().orElse(null);
        this.brain.setActiveActivityToFirstValid(ImmutableList.<Activity>of(Activity.FIGHT, Activity.IDLE));
        final Activity bfl3 = this.brain.getActiveNonCoreActivity().orElse(null);
        if (bfl3 == Activity.FIGHT && bfl2 != Activity.FIGHT) {
            this.playAngrySound();
        }
        this.setAggressive(this.brain.hasMemoryValue(MemoryModuleType.ATTACK_TARGET));
    }
    
    @Override
    protected void customServerAiStep() {
        this.level.getProfiler().push("zoglinBrain");
        this.getBrain().tick((ServerLevel)this.level, this);
        this.level.getProfiler().pop();
        this.updateActivity();
    }
    
    @Override
    public void setBaby(final boolean boolean1) {
        this.getEntityData().<Boolean>set(Zoglin.DATA_BABY_ID, boolean1);
        if (!this.level.isClientSide && boolean1) {
            this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(0.5);
        }
    }
    
    @Override
    public boolean isBaby() {
        return this.getEntityData().<Boolean>get(Zoglin.DATA_BABY_ID);
    }
    
    @Override
    public void aiStep() {
        if (this.attackAnimationRemainingTicks > 0) {
            --this.attackAnimationRemainingTicks;
        }
        super.aiStep();
    }
    
    @Override
    public void handleEntityEvent(final byte byte1) {
        if (byte1 == 4) {
            this.attackAnimationRemainingTicks = 10;
            this.playSound(SoundEvents.ZOGLIN_ATTACK, 1.0f, this.getVoicePitch());
        }
        else {
            super.handleEntityEvent(byte1);
        }
    }
    
    @Override
    public int getAttackAnimationRemainingTicks() {
        return this.attackAnimationRemainingTicks;
    }
    
    @Override
    protected SoundEvent getAmbientSound() {
        if (this.level.isClientSide) {
            return null;
        }
        if (this.brain.hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) {
            return SoundEvents.ZOGLIN_ANGRY;
        }
        return SoundEvents.ZOGLIN_AMBIENT;
    }
    
    @Override
    protected SoundEvent getHurtSound(final DamageSource anw) {
        return SoundEvents.ZOGLIN_HURT;
    }
    
    @Override
    protected SoundEvent getDeathSound() {
        return SoundEvents.ZOGLIN_DEATH;
    }
    
    @Override
    protected void playStepSound(final BlockPos fu, final BlockState cfj) {
        this.playSound(SoundEvents.ZOGLIN_STEP, 0.15f, 1.0f);
    }
    
    protected void playAngrySound() {
        this.playSound(SoundEvents.ZOGLIN_ANGRY, 1.0f, this.getVoicePitch());
    }
    
    @Override
    protected void sendDebugPackets() {
        super.sendDebugPackets();
        DebugPackets.sendEntityBrain(this);
    }
    
    @Override
    public MobType getMobType() {
        return MobType.UNDEAD;
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag le) {
        super.addAdditionalSaveData(le);
        if (this.isBaby()) {
            le.putBoolean("IsBaby", true);
        }
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag le) {
        super.readAdditionalSaveData(le);
        if (le.getBoolean("IsBaby")) {
            this.setBaby(true);
        }
    }
    
    static {
        DATA_BABY_ID = SynchedEntityData.<Boolean>defineId(Zoglin.class, EntityDataSerializers.BOOLEAN);
        SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS);
        MEMORY_TYPES = ImmutableList.of(MemoryModuleType.LIVING_ENTITIES, MemoryModuleType.VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_TARGETABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN);
    }
}
