package net.minecraft.world.entity.animal;

import net.minecraft.Util;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import net.minecraft.world.item.Items;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.world.entity.monster.Blaze;
import java.util.HashMap;
import net.minecraft.sounds.SoundSource;
import com.google.common.collect.Lists;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.LogBlock;
import net.minecraft.tags.BlockTags;
import java.util.Random;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.item.SpawnEggItem;
import net.minecraft.world.InteractionHand;
import java.util.List;
import net.minecraft.world.phys.Vec3;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.core.Position;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.monster.SharedMonsterAttributes;
import net.minecraft.world.entity.ai.goal.FollowMobGoal;
import net.minecraft.world.entity.ai.goal.LandOnOwnersShoulderGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomFlyingGoal;
import net.minecraft.world.entity.ai.goal.FollowOwnerGoal;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.ai.goal.PanicGoal;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.entity.ai.goal.SitGoal;
import net.minecraft.world.entity.AgableMob;
import net.minecraft.nbt.CompoundTag;
import javax.annotation.Nullable;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import net.minecraft.world.entity.ai.control.FlyingMoveControl;
import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.EntityType;
import java.util.Map;
import java.util.Set;
import net.minecraft.world.item.Item;
import net.minecraft.world.entity.Mob;
import java.util.function.Predicate;
import net.minecraft.network.syncher.EntityDataAccessor;

public class Parrot extends ShoulderRidingEntity implements FlyingAnimal {
    private static final EntityDataAccessor<Integer> DATA_VARIANT_ID;
    private static final Predicate<Mob> NOT_PARROT_PREDICATE;
    private static final Item POISONOUS_FOOD;
    private static final Set<Item> TAME_FOOD;
    private static final Map<EntityType<?>, SoundEvent> MOB_SOUND_MAP;
    public float flap;
    public float flapSpeed;
    public float oFlapSpeed;
    public float oFlap;
    private float flapping;
    private boolean partyParrot;
    private BlockPos jukebox;
    
    public Parrot(final EntityType<? extends Parrot> aku, final Level bjw) {
        super(aku, bjw);
        this.flapping = 1.0f;
        this.moveControl = new FlyingMoveControl(this, 10, false);
        this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0f);
        this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, -1.0f);
        this.setPathfindingMalus(BlockPathTypes.COCOA, -1.0f);
    }
    
    @Nullable
    @Override
    public SpawnGroupData finalizeSpawn(final LevelAccessor bjx, final DifficultyInstance ajj, final MobSpawnType alc, @Nullable SpawnGroupData alm, @Nullable final CompoundTag jt) {
        this.setVariant(this.random.nextInt(5));
        if (alm == null) {
            alm = new AgableMobGroupData();
            ((AgableMobGroupData)alm).setShouldSpawnBaby(false);
        }
        return super.finalizeSpawn(bjx, ajj, alc, alm, jt);
    }
    
    @Override
    protected void registerGoals() {
        this.sitGoal = new SitGoal(this);
        this.goalSelector.addGoal(0, new PanicGoal(this, 1.25));
        this.goalSelector.addGoal(0, new FloatGoal(this));
        this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0f));
        this.goalSelector.addGoal(2, this.sitGoal);
        this.goalSelector.addGoal(2, new FollowOwnerGoal(this, 1.0, 5.0f, 1.0f, true));
        this.goalSelector.addGoal(2, new WaterAvoidingRandomFlyingGoal(this, 1.0));
        this.goalSelector.addGoal(3, new LandOnOwnersShoulderGoal(this));
        this.goalSelector.addGoal(3, new FollowMobGoal(this, 1.0, 3.0f, 7.0f));
    }
    
    @Override
    protected void registerAttributes() {
        super.registerAttributes();
        this.getAttributes().registerAttribute(SharedMonsterAttributes.FLYING_SPEED);
        this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(6.0);
        this.getAttribute(SharedMonsterAttributes.FLYING_SPEED).setBaseValue(0.4000000059604645);
        this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.20000000298023224);
    }
    
    @Override
    protected PathNavigation createNavigation(final Level bjw) {
        final FlyingPathNavigation arp3 = new FlyingPathNavigation(this, bjw);
        arp3.setCanOpenDoors(false);
        arp3.setCanFloat(true);
        arp3.setCanPassDoors(true);
        return arp3;
    }
    
    @Override
    protected float getStandingEyeHeight(final Pose alj, final EntityDimensions akr) {
        return akr.height * 0.6f;
    }
    
    @Override
    public void aiStep() {
        imitateNearbyMobs(this.level, this);
        if (this.jukebox == null || !this.jukebox.closerThan(this.position(), 3.46) || this.level.getBlockState(this.jukebox).getBlock() != Blocks.JUKEBOX) {
            this.partyParrot = false;
            this.jukebox = null;
        }
        super.aiStep();
        this.calculateFlapping();
    }
    
    @Override
    public void setRecordPlayingNearby(final BlockPos fk, final boolean boolean2) {
        this.jukebox = fk;
        this.partyParrot = boolean2;
    }
    
    public boolean isPartyParrot() {
        return this.partyParrot;
    }
    
    private void calculateFlapping() {
        this.oFlap = this.flap;
        this.oFlapSpeed = this.flapSpeed;
        this.flapSpeed += (float)(((this.onGround || this.isPassenger()) ? -1 : 4) * 0.3);
        this.flapSpeed = Mth.clamp(this.flapSpeed, 0.0f, 1.0f);
        if (!this.onGround && this.flapping < 1.0f) {
            this.flapping = 1.0f;
        }
        this.flapping *= (float)0.9;
        final Vec3 cvl2 = this.getDeltaMovement();
        if (!this.onGround && cvl2.y < 0.0) {
            this.setDeltaMovement(cvl2.multiply(1.0, 0.6, 1.0));
        }
        this.flap += this.flapping * 2.0f;
    }
    
    private static boolean imitateNearbyMobs(final Level bjw, final Entity akq) {
        if (!akq.isAlive() || akq.isSilent() || bjw.random.nextInt(50) != 0) {
            return false;
        }
        final List<Mob> list3 = bjw.<Mob>getEntitiesOfClass(Mob.class, akq.getBoundingBox().inflate(20.0), Parrot.NOT_PARROT_PREDICATE);
        if (!list3.isEmpty()) {
            final Mob ala4 = list3.get(bjw.random.nextInt(list3.size()));
            if (!ala4.isSilent()) {
                final SoundEvent aah5 = getImitatedSound(ala4.getType());
                bjw.playSound(null, akq.getX(), akq.getY(), akq.getZ(), aah5, akq.getSoundSource(), 0.7f, getPitch(bjw.random));
                return true;
            }
        }
        return false;
    }
    
    @Override
    public boolean mobInteract(final Player ayj, final InteractionHand ajk) {
        final ItemStack ben4 = ayj.getItemInHand(ajk);
        if (ben4.getItem() instanceof SpawnEggItem) {
            return super.mobInteract(ayj, ajk);
        }
        if (!this.isTame() && Parrot.TAME_FOOD.contains(ben4.getItem())) {
            if (!ayj.abilities.instabuild) {
                ben4.shrink(1);
            }
            if (!this.isSilent()) {
                this.level.playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PARROT_EAT, this.getSoundSource(), 1.0f, 1.0f + (this.random.nextFloat() - this.random.nextFloat()) * 0.2f);
            }
            if (!this.level.isClientSide) {
                if (this.random.nextInt(10) == 0) {
                    this.tame(ayj);
                    this.level.broadcastEntityEvent(this, (byte)7);
                }
                else {
                    this.level.broadcastEntityEvent(this, (byte)6);
                }
            }
            return true;
        }
        if (ben4.getItem() == Parrot.POISONOUS_FOOD) {
            if (!ayj.abilities.instabuild) {
                ben4.shrink(1);
            }
            this.addEffect(new MobEffectInstance(MobEffects.POISON, 900));
            if (ayj.isCreative() || !this.isInvulnerable()) {
                this.hurt(DamageSource.playerAttack(ayj), Float.MAX_VALUE);
            }
            return true;
        }
        if (!this.isFlying() && this.isTame() && this.isOwnedBy(ayj)) {
            if (!this.level.isClientSide) {
                this.sitGoal.wantToSit(!this.isSitting());
            }
            return true;
        }
        return super.mobInteract(ayj, ajk);
    }
    
    @Override
    public boolean isFood(final ItemStack ben) {
        return false;
    }
    
    public static boolean checkParrotSpawnRules(final EntityType<Parrot> aku, final LevelAccessor bjx, final MobSpawnType alc, final BlockPos fk, final Random random) {
        final Block bph6 = bjx.getBlockState(fk.below()).getBlock();
        return (bph6.is(BlockTags.LEAVES) || bph6 == Blocks.GRASS_BLOCK || bph6 instanceof LogBlock || bph6 == Blocks.AIR) && bjx.getRawBrightness(fk, 0) > 8;
    }
    
    @Override
    public boolean causeFallDamage(final float float1, final float float2) {
        return false;
    }
    
    @Override
    protected void checkFallDamage(final double double1, final boolean boolean2, final BlockState byj, final BlockPos fk) {
    }
    
    @Override
    public boolean canMate(final Animal atc) {
        return false;
    }
    
    @Nullable
    @Override
    public AgableMob getBreedOffspring(final AgableMob ako) {
        return null;
    }
    
    public static void playAmbientSound(final Level bjw, final Entity akq) {
        if (!akq.isSilent() && !imitateNearbyMobs(bjw, akq) && bjw.random.nextInt(200) == 0) {
            bjw.playSound(null, akq.getX(), akq.getY(), akq.getZ(), getAmbient(bjw.random), akq.getSoundSource(), 1.0f, getPitch(bjw.random));
        }
    }
    
    @Override
    public boolean doHurtTarget(final Entity akq) {
        return akq.hurt(DamageSource.mobAttack(this), 3.0f);
    }
    
    @Nullable
    public SoundEvent getAmbientSound() {
        return getAmbient(this.random);
    }
    
    private static SoundEvent getAmbient(final Random random) {
        if (random.nextInt(1000) == 0) {
            final List<EntityType<?>> list2 = Lists.newArrayList(Parrot.MOB_SOUND_MAP.keySet());
            return getImitatedSound(list2.get(random.nextInt(list2.size())));
        }
        return SoundEvents.PARROT_AMBIENT;
    }
    
    private static SoundEvent getImitatedSound(final EntityType<?> aku) {
        return Parrot.MOB_SOUND_MAP.getOrDefault(aku, SoundEvents.PARROT_AMBIENT);
    }
    
    @Override
    protected SoundEvent getHurtSound(final DamageSource ajz) {
        return SoundEvents.PARROT_HURT;
    }
    
    @Override
    protected SoundEvent getDeathSound() {
        return SoundEvents.PARROT_DEATH;
    }
    
    @Override
    protected void playStepSound(final BlockPos fk, final BlockState byj) {
        this.playSound(SoundEvents.PARROT_STEP, 0.15f, 1.0f);
    }
    
    @Override
    protected float playFlySound(final float float1) {
        this.playSound(SoundEvents.PARROT_FLY, 0.15f, 1.0f);
        return float1 + this.flapSpeed / 2.0f;
    }
    
    @Override
    protected boolean makeFlySound() {
        return true;
    }
    
    @Override
    protected float getVoicePitch() {
        return getPitch(this.random);
    }
    
    private static float getPitch(final Random random) {
        return (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f;
    }
    
    @Override
    public SoundSource getSoundSource() {
        return SoundSource.NEUTRAL;
    }
    
    @Override
    public boolean isPushable() {
        return true;
    }
    
    @Override
    protected void doPush(final Entity akq) {
        if (akq instanceof Player) {
            return;
        }
        super.doPush(akq);
    }
    
    @Override
    public boolean hurt(final DamageSource ajz, final float float2) {
        if (this.isInvulnerableTo(ajz)) {
            return false;
        }
        if (this.sitGoal != null) {
            this.sitGoal.wantToSit(false);
        }
        return super.hurt(ajz, float2);
    }
    
    public int getVariant() {
        return Mth.clamp(this.entityData.<Integer>get(Parrot.DATA_VARIANT_ID), 0, 4);
    }
    
    public void setVariant(final int integer) {
        this.entityData.<Integer>set(Parrot.DATA_VARIANT_ID, integer);
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Integer>define(Parrot.DATA_VARIANT_ID, 0);
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag jt) {
        super.addAdditionalSaveData(jt);
        jt.putInt("Variant", this.getVariant());
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        super.readAdditionalSaveData(jt);
        this.setVariant(jt.getInt("Variant"));
    }
    
    public boolean isFlying() {
        return !this.onGround;
    }
    
    static {
        DATA_VARIANT_ID = SynchedEntityData.<Integer>defineId(Parrot.class, EntityDataSerializers.INT);
        NOT_PARROT_PREDICATE = new Predicate<Mob>() {
            @Override
            public boolean test(@Nullable final Mob ala) {
                return ala != null && Parrot.MOB_SOUND_MAP.containsKey(ala.getType());
            }
        };
        POISONOUS_FOOD = Items.COOKIE;
        TAME_FOOD = Sets.<Item>newHashSet(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS);
        MOB_SOUND_MAP = Util.<Map<EntityType<?>, SoundEvent>>make(Maps.newHashMap(), hashMap -> {
            hashMap.put(EntityType.BLAZE, SoundEvents.PARROT_IMITATE_BLAZE);
            hashMap.put((EntityType<Blaze>)EntityType.CAVE_SPIDER, SoundEvents.PARROT_IMITATE_SPIDER);
            hashMap.put((EntityType<Blaze>)EntityType.CREEPER, SoundEvents.PARROT_IMITATE_CREEPER);
            hashMap.put((EntityType<Blaze>)EntityType.DROWNED, SoundEvents.PARROT_IMITATE_DROWNED);
            hashMap.put((EntityType<Blaze>)EntityType.ELDER_GUARDIAN, SoundEvents.PARROT_IMITATE_ELDER_GUARDIAN);
            hashMap.put((EntityType<Blaze>)EntityType.ENDER_DRAGON, SoundEvents.PARROT_IMITATE_ENDER_DRAGON);
            hashMap.put((EntityType<Blaze>)EntityType.ENDERMITE, SoundEvents.PARROT_IMITATE_ENDERMITE);
            hashMap.put((EntityType<Blaze>)EntityType.EVOKER, SoundEvents.PARROT_IMITATE_EVOKER);
            hashMap.put((EntityType<Blaze>)EntityType.GHAST, SoundEvents.PARROT_IMITATE_GHAST);
            hashMap.put((EntityType<Blaze>)EntityType.GUARDIAN, SoundEvents.PARROT_IMITATE_GUARDIAN);
            hashMap.put((EntityType<Blaze>)EntityType.HUSK, SoundEvents.PARROT_IMITATE_HUSK);
            hashMap.put((EntityType<Blaze>)EntityType.ILLUSIONER, SoundEvents.PARROT_IMITATE_ILLUSIONER);
            hashMap.put((EntityType<Blaze>)EntityType.MAGMA_CUBE, SoundEvents.PARROT_IMITATE_MAGMA_CUBE);
            hashMap.put((EntityType<Blaze>)EntityType.PHANTOM, SoundEvents.PARROT_IMITATE_PHANTOM);
            hashMap.put((EntityType<Blaze>)EntityType.PILLAGER, SoundEvents.PARROT_IMITATE_PILLAGER);
            hashMap.put((EntityType<Blaze>)EntityType.RAVAGER, SoundEvents.PARROT_IMITATE_RAVAGER);
            hashMap.put((EntityType<Blaze>)EntityType.SHULKER, SoundEvents.PARROT_IMITATE_SHULKER);
            hashMap.put((EntityType<Blaze>)EntityType.SILVERFISH, SoundEvents.PARROT_IMITATE_SILVERFISH);
            hashMap.put((EntityType<Blaze>)EntityType.SKELETON, SoundEvents.PARROT_IMITATE_SKELETON);
            hashMap.put((EntityType<Blaze>)EntityType.SLIME, SoundEvents.PARROT_IMITATE_SLIME);
            hashMap.put((EntityType<Blaze>)EntityType.SPIDER, SoundEvents.PARROT_IMITATE_SPIDER);
            hashMap.put((EntityType<Blaze>)EntityType.STRAY, SoundEvents.PARROT_IMITATE_STRAY);
            hashMap.put((EntityType<Blaze>)EntityType.VEX, SoundEvents.PARROT_IMITATE_VEX);
            hashMap.put((EntityType<Blaze>)EntityType.VINDICATOR, SoundEvents.PARROT_IMITATE_VINDICATOR);
            hashMap.put((EntityType<Blaze>)EntityType.WITCH, SoundEvents.PARROT_IMITATE_WITCH);
            hashMap.put((EntityType<Blaze>)EntityType.WITHER, SoundEvents.PARROT_IMITATE_WITHER);
            hashMap.put((EntityType<Blaze>)EntityType.WITHER_SKELETON, SoundEvents.PARROT_IMITATE_WITHER_SKELETON);
            hashMap.put((EntityType<Blaze>)EntityType.ZOMBIE, SoundEvents.PARROT_IMITATE_ZOMBIE);
            hashMap.put((EntityType<Blaze>)EntityType.ZOMBIE_VILLAGER, SoundEvents.PARROT_IMITATE_ZOMBIE_VILLAGER);
        });
    }
}
