package net.minecraft.world.entity.monster.piglin;

import net.minecraft.world.entity.ai.behavior.PositionTracker;
import net.minecraft.world.entity.ai.sensing.NearestLivingEntitySensor;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.sounds.SoundEvent;
import java.util.List;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.item.ProjectileWeaponItem;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.TieredItem;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.monster.ZombifiedPiglin;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import com.mojang.serialization.Dynamic;
import java.util.Collection;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.Items;
import net.minecraft.world.entity.EquipmentSlot;
import javax.annotation.Nullable;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.level.block.Blocks;
import java.util.Random;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.item.ItemStack;
import java.util.function.Consumer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
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.world.SimpleContainer;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import java.util.UUID;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.monster.CrossbowAttackMob;
import net.minecraft.world.entity.monster.Monster;

public class Piglin extends Monster implements CrossbowAttackMob {
    private static final EntityDataAccessor<Boolean> DATA_BABY_ID;
    private static final EntityDataAccessor<Boolean> DATA_IMMUNE_TO_ZOMBIFICATION;
    private static final EntityDataAccessor<Boolean> DATA_IS_CHARGING_CROSSBOW;
    private static final EntityDataAccessor<Boolean> DATA_IS_DANCING;
    private static final UUID SPEED_MODIFIER_BABY_UUID;
    private static final AttributeModifier SPEED_MODIFIER_BABY;
    private int timeInOverworld;
    private final SimpleContainer inventory;
    private boolean cannotHunt;
    protected static final ImmutableList<SensorType<? extends Sensor<? super Piglin>>> SENSOR_TYPES;
    protected static final ImmutableList<MemoryModuleType<?>> MEMORY_TYPES;
    
    public Piglin(final EntityType<? extends Monster> aoq, final Level bqb) {
        super(aoq, bqb);
        this.timeInOverworld = 0;
        this.inventory = new SimpleContainer(8);
        this.cannotHunt = false;
        this.setCanPickUpLoot(true);
        ((GroundPathNavigation)this.getNavigation()).setCanOpenDoors(true);
        this.xpReward = 5;
        this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 16.0f);
        this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, -1.0f);
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag le) {
        super.addAdditionalSaveData(le);
        if (this.isBaby()) {
            le.putBoolean("IsBaby", true);
        }
        if (this.isImmuneToZombification()) {
            le.putBoolean("IsImmuneToZombification", true);
        }
        if (this.cannotHunt) {
            le.putBoolean("CannotHunt", true);
        }
        le.putInt("TimeInOverworld", this.timeInOverworld);
        le.put("Inventory", this.inventory.createTag());
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag le) {
        super.readAdditionalSaveData(le);
        this.setBaby(le.getBoolean("IsBaby"));
        this.setImmuneToZombification(le.getBoolean("IsImmuneToZombification"));
        this.setCannotHunt(le.getBoolean("CannotHunt"));
        this.timeInOverworld = le.getInt("TimeInOverworld");
        this.inventory.fromTag(le.getList("Inventory", 10));
    }
    
    @Override
    protected void dropCustomDeathLoot(final DamageSource anw, final int integer, final boolean boolean3) {
        super.dropCustomDeathLoot(anw, integer, boolean3);
        this.inventory.removeAllItems().forEach(this::spawnAtLocation);
    }
    
    protected ItemStack addToInventory(final ItemStack bki) {
        return this.inventory.addItem(bki);
    }
    
    protected boolean canAddToInventory(final ItemStack bki) {
        return this.inventory.canAddItem(bki);
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Boolean>define(Piglin.DATA_BABY_ID, false);
        this.entityData.<Boolean>define(Piglin.DATA_IS_CHARGING_CROSSBOW, false);
        this.entityData.<Boolean>define(Piglin.DATA_IMMUNE_TO_ZOMBIFICATION, false);
        this.entityData.<Boolean>define(Piglin.DATA_IS_DANCING, false);
    }
    
    @Override
    public void onSyncedDataUpdated(final EntityDataAccessor<?> tq) {
        super.onSyncedDataUpdated(tq);
        if (Piglin.DATA_BABY_ID.equals(tq)) {
            this.refreshDimensions();
        }
    }
    
    public static AttributeSupplier.Builder createAttributes() {
        return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 16.0).add(Attributes.MOVEMENT_SPEED, 0.3499999940395355).add(Attributes.ATTACK_DAMAGE, 5.0);
    }
    
    public static boolean checkPiglinSpawnRules(final EntityType<Piglin> aoq, final LevelAccessor bqc, final MobSpawnType apb, final BlockPos fu, final Random random) {
        return !bqc.getBlockState(fu.below()).is(Blocks.NETHER_WART_BLOCK);
    }
    
    @Nullable
    @Override
    public SpawnGroupData finalizeSpawn(final LevelAccessor bqc, final DifficultyInstance ane, final MobSpawnType apb, @Nullable final SpawnGroupData apo, @Nullable final CompoundTag le) {
        if (apb != MobSpawnType.STRUCTURE) {
            if (bqc.getRandom().nextFloat() < 0.2f) {
                this.setBaby(true);
            }
            else if (this.isAdult()) {
                this.setItemSlot(EquipmentSlot.MAINHAND, this.createSpawnWeapon());
            }
        }
        PiglinAi.initMemories(this);
        this.populateDefaultEquipmentSlots(ane);
        this.populateDefaultEquipmentEnchantments(ane);
        return super.finalizeSpawn(bqc, ane, apb, apo, le);
    }
    
    @Override
    protected boolean shouldDespawnInPeaceful() {
        return false;
    }
    
    @Override
    public boolean removeWhenFarAway(final double double1) {
        return !this.isPersistenceRequired();
    }
    
    @Override
    protected void populateDefaultEquipmentSlots(final DifficultyInstance ane) {
        if (this.isAdult()) {
            this.maybeWearArmor(EquipmentSlot.HEAD, new ItemStack(Items.GOLDEN_HELMET));
            this.maybeWearArmor(EquipmentSlot.CHEST, new ItemStack(Items.GOLDEN_CHESTPLATE));
            this.maybeWearArmor(EquipmentSlot.LEGS, new ItemStack(Items.GOLDEN_LEGGINGS));
            this.maybeWearArmor(EquipmentSlot.FEET, new ItemStack(Items.GOLDEN_BOOTS));
        }
    }
    
    private void maybeWearArmor(final EquipmentSlot aor, final ItemStack bki) {
        if (this.level.random.nextFloat() < 0.1f) {
            this.setItemSlot(aor, bki);
        }
    }
    
    @Override
    protected Brain.Provider<Piglin> brainProvider() {
        return Brain.<Piglin>provider(Piglin.MEMORY_TYPES, Piglin.SENSOR_TYPES);
    }
    
    @Override
    protected Brain<?> makeBrain(final Dynamic<?> dynamic) {
        return PiglinAi.makeBrain(this, this.brainProvider().makeBrain(dynamic));
    }
    
    @Override
    public Brain<Piglin> getBrain() {
        return (Brain<Piglin>)super.getBrain();
    }
    
    public InteractionResult mobInteract(final Player bec, final InteractionHand anf) {
        final InteractionResult ang4 = super.mobInteract(bec, anf);
        if (ang4.consumesAction()) {
            return ang4;
        }
        if (this.level.isClientSide) {
            final boolean boolean5 = PiglinAi.canAdmire(this, bec.getItemInHand(anf)) && this.getArmPose() != PiglinArmPose.ADMIRING_ITEM;
            return boolean5 ? InteractionResult.SUCCESS : InteractionResult.PASS;
        }
        return PiglinAi.mobInteract(this, bec, anf);
    }
    
    @Override
    protected float getStandingEyeHeight(final Pose apj, final EntityDimensions aon) {
        return this.isBaby() ? 0.93f : 1.74f;
    }
    
    @Override
    public double getMyRidingOffset() {
        return this.isBaby() ? -0.1 : -0.45;
    }
    
    @Override
    public double getPassengersRidingOffset() {
        return this.getBbHeight() * 0.92;
    }
    
    @Override
    public void setBaby(final boolean boolean1) {
        this.getEntityData().<Boolean>set(Piglin.DATA_BABY_ID, boolean1);
        if (!this.level.isClientSide) {
            final AttributeInstance apt3 = this.getAttribute(Attributes.MOVEMENT_SPEED);
            apt3.removeModifier(Piglin.SPEED_MODIFIER_BABY);
            if (boolean1) {
                apt3.addTransientModifier(Piglin.SPEED_MODIFIER_BABY);
            }
        }
    }
    
    @Override
    public boolean isBaby() {
        return this.getEntityData().<Boolean>get(Piglin.DATA_BABY_ID);
    }
    
    public boolean isAdult() {
        return !this.isBaby();
    }
    
    public void setImmuneToZombification(final boolean boolean1) {
        this.getEntityData().<Boolean>set(Piglin.DATA_IMMUNE_TO_ZOMBIFICATION, boolean1);
    }
    
    private boolean isImmuneToZombification() {
        return this.getEntityData().<Boolean>get(Piglin.DATA_IMMUNE_TO_ZOMBIFICATION);
    }
    
    private void setCannotHunt(final boolean boolean1) {
        this.cannotHunt = boolean1;
    }
    
    protected boolean canHunt() {
        return !this.cannotHunt;
    }
    
    public boolean isConverting() {
        return !this.level.dimensionType().piglinSafe() && !this.isImmuneToZombification() && !this.isNoAi();
    }
    
    @Override
    protected void customServerAiStep() {
        this.level.getProfiler().push("piglinBrain");
        this.getBrain().tick((ServerLevel)this.level, this);
        this.level.getProfiler().pop();
        PiglinAi.updateActivity(this);
        if (this.isConverting()) {
            ++this.timeInOverworld;
        }
        else {
            this.timeInOverworld = 0;
        }
        if (this.timeInOverworld > 300) {
            this.playSound(SoundEvents.PIGLIN_CONVERTED_TO_ZOMBIFIED);
            this.finishConversion((ServerLevel)this.level);
        }
    }
    
    @Override
    protected int getExperienceReward(final Player bec) {
        return this.xpReward;
    }
    
    private void finishConversion(final ServerLevel zd) {
        PiglinAi.cancelAdmiring(this);
        this.inventory.removeAllItems().forEach(this::spawnAtLocation);
        final ZombifiedPiglin bcw3 = this.<ZombifiedPiglin>convertTo(EntityType.ZOMBIFIED_PIGLIN);
        bcw3.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0));
    }
    
    @Nullable
    @Override
    public LivingEntity getTarget() {
        return this.brain.<LivingEntity>getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null);
    }
    
    private ItemStack createSpawnWeapon() {
        if (this.random.nextFloat() < 0.5) {
            return new ItemStack(Items.CROSSBOW);
        }
        return new ItemStack(Items.GOLDEN_SWORD);
    }
    
    private boolean isChargingCrossbow() {
        return this.entityData.<Boolean>get(Piglin.DATA_IS_CHARGING_CROSSBOW);
    }
    
    @Override
    public void setChargingCrossbow(final boolean boolean1) {
        this.entityData.<Boolean>set(Piglin.DATA_IS_CHARGING_CROSSBOW, boolean1);
    }
    
    @Override
    public void onCrossbowAttackPerformed() {
        this.noActionTime = 0;
    }
    
    public PiglinArmPose getArmPose() {
        if (this.isDancing()) {
            return PiglinArmPose.DANCING;
        }
        if (PiglinAi.isLovedItem(this.getOffhandItem().getItem())) {
            return PiglinArmPose.ADMIRING_ITEM;
        }
        if (this.isAggressive() && this.isHoldingMeleeWeapon()) {
            return PiglinArmPose.ATTACKING_WITH_MELEE_WEAPON;
        }
        if (this.isChargingCrossbow()) {
            return PiglinArmPose.CROSSBOW_CHARGE;
        }
        if (this.isAggressive() && this.isHolding(Items.CROSSBOW)) {
            return PiglinArmPose.CROSSBOW_HOLD;
        }
        return PiglinArmPose.DEFAULT;
    }
    
    public boolean isDancing() {
        return this.entityData.<Boolean>get(Piglin.DATA_IS_DANCING);
    }
    
    public void setDancing(final boolean boolean1) {
        this.entityData.<Boolean>set(Piglin.DATA_IS_DANCING, boolean1);
    }
    
    private boolean isHoldingMeleeWeapon() {
        return this.getMainHandItem().getItem() instanceof TieredItem;
    }
    
    @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) {
            PiglinAi.wasHurtBy(this, (LivingEntity)anw.getEntity());
        }
        return boolean4;
    }
    
    @Override
    public void performRangedAttack(final LivingEntity aoy, final float float2) {
        this.performCrossbowAttack(this, 1.6f);
    }
    
    @Override
    public void shootCrossbowProjectile(final LivingEntity aoy, final ItemStack bki, final Projectile bes, final float float4) {
        this.shootCrossbowProjectile(this, aoy, bes, float4, 1.6f);
    }
    
    @Override
    public boolean canFireProjectileWeapon(final ProjectileWeaponItem bkv) {
        return bkv == Items.CROSSBOW;
    }
    
    protected void holdInMainHand(final ItemStack bki) {
        this.setItemSlotAndDropWhenKilled(EquipmentSlot.MAINHAND, bki);
    }
    
    protected void holdInOffHand(final ItemStack bki) {
        if (bki.getItem() == PiglinAi.BARTERING_ITEM) {
            this.setItemSlot(EquipmentSlot.OFFHAND, bki);
            this.setGuaranteedDrop(EquipmentSlot.OFFHAND);
        }
        else {
            this.setItemSlotAndDropWhenKilled(EquipmentSlot.OFFHAND, bki);
        }
    }
    
    @Override
    public boolean wantsToPickUp(final ItemStack bki) {
        return this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && PiglinAi.wantsToPickup(this, bki);
    }
    
    protected boolean canReplaceCurrentItem(final ItemStack bki) {
        final EquipmentSlot aor3 = Mob.getEquipmentSlotForItem(bki);
        final ItemStack bki2 = this.getItemBySlot(aor3);
        return this.canReplaceCurrentItem(bki, bki2);
    }
    
    @Override
    protected boolean canReplaceCurrentItem(final ItemStack bki1, final ItemStack bki2) {
        if (EnchantmentHelper.hasBindingCurse(bki2)) {
            return false;
        }
        final boolean boolean4 = PiglinAi.isLovedItem(bki1.getItem()) || bki1.getItem() == Items.CROSSBOW;
        final boolean boolean5 = PiglinAi.isLovedItem(bki2.getItem()) || bki2.getItem() == Items.CROSSBOW;
        return (boolean4 && !boolean5) || ((boolean4 || !boolean5) && (!this.isAdult() || bki1.getItem() == Items.CROSSBOW || bki2.getItem() != Items.CROSSBOW) && super.canReplaceCurrentItem(bki1, bki2));
    }
    
    @Override
    protected void pickUpItem(final ItemEntity bbg) {
        this.onItemPickup(bbg);
        PiglinAi.pickUpItem(this, bbg);
    }
    
    @Override
    public boolean startRiding(Entity aom, final boolean boolean2) {
        if (this.isBaby() && aom.getType() == EntityType.HOGLIN) {
            aom = this.getTopPassenger(aom, 3);
        }
        return super.startRiding(aom, boolean2);
    }
    
    private Entity getTopPassenger(final Entity aom, final int integer) {
        final List<Entity> list4 = aom.getPassengers();
        if (integer == 1 || list4.isEmpty()) {
            return aom;
        }
        return this.getTopPassenger(list4.get(0), integer - 1);
    }
    
    @Override
    protected SoundEvent getAmbientSound() {
        if (this.level.isClientSide) {
            return null;
        }
        return PiglinAi.getSoundForCurrentActivity(this).orElse(null);
    }
    
    @Override
    protected SoundEvent getHurtSound(final DamageSource anw) {
        return SoundEvents.PIGLIN_HURT;
    }
    
    @Override
    protected SoundEvent getDeathSound() {
        return SoundEvents.PIGLIN_DEATH;
    }
    
    @Override
    protected void playStepSound(final BlockPos fu, final BlockState cfj) {
        this.playSound(SoundEvents.PIGLIN_STEP, 0.15f, 1.0f);
    }
    
    protected void playSound(final SoundEvent ack) {
        this.playSound(ack, this.getSoundVolume(), this.getVoicePitch());
    }
    
    @Override
    protected void sendDebugPackets() {
        super.sendDebugPackets();
        DebugPackets.sendEntityBrain(this);
    }
    
    static {
        DATA_BABY_ID = SynchedEntityData.<Boolean>defineId(Piglin.class, EntityDataSerializers.BOOLEAN);
        DATA_IMMUNE_TO_ZOMBIFICATION = SynchedEntityData.<Boolean>defineId(Piglin.class, EntityDataSerializers.BOOLEAN);
        DATA_IS_CHARGING_CROSSBOW = SynchedEntityData.<Boolean>defineId(Piglin.class, EntityDataSerializers.BOOLEAN);
        DATA_IS_DANCING = SynchedEntityData.<Boolean>defineId(Piglin.class, EntityDataSerializers.BOOLEAN);
        SPEED_MODIFIER_BABY_UUID = UUID.fromString("766bfa64-11f3-11ea-8d71-362b9e155667");
        SPEED_MODIFIER_BABY = new AttributeModifier(Piglin.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.20000000298023224, AttributeModifier.Operation.MULTIPLY_BASE);
        SENSOR_TYPES = ImmutableList.<SensorType<NearestLivingEntitySensor>>of(SensorType.NEAREST_LIVING_ENTITIES, (SensorType<NearestLivingEntitySensor>)SensorType.NEAREST_PLAYERS, (SensorType<NearestLivingEntitySensor>)SensorType.NEAREST_ITEMS, (SensorType<NearestLivingEntitySensor>)SensorType.HURT_BY, (SensorType<NearestLivingEntitySensor>)SensorType.INTERACTABLE_DOORS, (SensorType<NearestLivingEntitySensor>)SensorType.PIGLIN_SPECIFIC_SENSOR);
        MEMORY_TYPES = ImmutableList.<MemoryModuleType<PositionTracker>>of(MemoryModuleType.LOOK_TARGET, (MemoryModuleType<PositionTracker>)MemoryModuleType.INTERACTABLE_DOORS, (MemoryModuleType<PositionTracker>)MemoryModuleType.OPENED_DOORS, (MemoryModuleType<PositionTracker>)MemoryModuleType.LIVING_ENTITIES, (MemoryModuleType<PositionTracker>)MemoryModuleType.VISIBLE_LIVING_ENTITIES, (MemoryModuleType<PositionTracker>)MemoryModuleType.NEAREST_VISIBLE_PLAYER, (MemoryModuleType<PositionTracker>)MemoryModuleType.NEAREST_VISIBLE_TARGETABLE_PLAYER, (MemoryModuleType<PositionTracker>)MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, (MemoryModuleType<PositionTracker>)MemoryModuleType.NEAREST_ADULT_PIGLINS, (MemoryModuleType<PositionTracker>)MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, (MemoryModuleType<PositionTracker>)MemoryModuleType.HURT_BY, (MemoryModuleType<PositionTracker>)MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.INTERACTION_TARGET, MemoryModuleType.PATH, MemoryModuleType.ANGRY_AT, MemoryModuleType.UNIVERSAL_ANGER, MemoryModuleType.AVOID_TARGET, MemoryModuleType.ADMIRING_ITEM, MemoryModuleType.ADMIRING_DISABLED, MemoryModuleType.CELEBRATE_LOCATION, MemoryModuleType.DANCING, MemoryModuleType.HUNTED_RECENTLY, MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, MemoryModuleType.NEAREST_VISIBLE_BABY_PIGLIN, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, MemoryModuleType.RIDE_TARGET, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, MemoryModuleType.ATE_RECENTLY, MemoryModuleType.NEAREST_REPELLENT);
    }
    
    public enum PiglinArmPose {
        ATTACKING_WITH_MELEE_WEAPON, 
        CROSSBOW_HOLD, 
        CROSSBOW_CHARGE, 
        ADMIRING_ITEM, 
        DANCING, 
        DEFAULT;
    }
}
