package net.minecraft.world.entity.animal;

import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import java.util.Random;
import net.minecraft.world.entity.animal.horse.AbstractHorse;
import net.minecraft.world.entity.monster.Ghast;
import net.minecraft.world.entity.monster.Creeper;
import java.util.UUID;
import net.minecraft.world.entity.AgableMob;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.DyeItem;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.SpawnEggItem;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.phys.Vec3;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.DyeColor;
import javax.annotation.Nullable;
import net.minecraft.world.entity.monster.SharedMonsterAttributes;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.monster.AbstractSkeleton;
import net.minecraft.world.entity.ai.goal.target.NonTameRandomTargetGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.OwnerHurtTargetGoal;
import net.minecraft.world.entity.ai.goal.target.OwnerHurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.ai.goal.BegGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.goal.BreedGoal;
import net.minecraft.world.entity.ai.goal.FollowOwnerGoal;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.world.entity.ai.goal.LeapAtTargetGoal;
import net.minecraft.world.entity.animal.horse.Llama;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.SitGoal;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import java.util.function.Predicate;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.TamableAnimal;

public class Wolf extends TamableAnimal {
    private static final EntityDataAccessor<Boolean> DATA_INTERESTED_ID;
    private static final EntityDataAccessor<Integer> DATA_COLLAR_COLOR;
    public static final Predicate<LivingEntity> PREY_SELECTOR;
    private float interestedAngle;
    private float interestedAngleO;
    private boolean isWet;
    private boolean isShaking;
    private float shakeAnim;
    private float shakeAnimO;
    
    public Wolf(final EntityType<? extends Wolf> aku, final Level bjw) {
        super(aku, bjw);
        this.setTame(false);
    }
    
    @Override
    protected void registerGoals() {
        this.sitGoal = new SitGoal(this);
        this.goalSelector.addGoal(1, new FloatGoal(this));
        this.goalSelector.addGoal(2, this.sitGoal);
        this.goalSelector.addGoal(3, new WolfAvoidEntityGoal<>(this, Llama.class, 24.0f, 1.5, 1.5));
        this.goalSelector.addGoal(4, new LeapAtTargetGoal(this, 0.4f));
        this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0, true));
        this.goalSelector.addGoal(6, new FollowOwnerGoal(this, 1.0, 10.0f, 2.0f, false));
        this.goalSelector.addGoal(7, new BreedGoal(this, 1.0));
        this.goalSelector.addGoal(8, new WaterAvoidingRandomStrollGoal(this, 1.0));
        this.goalSelector.addGoal(9, new BegGoal(this, 8.0f));
        this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Player.class, 8.0f));
        this.goalSelector.addGoal(10, new RandomLookAroundGoal(this));
        this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this));
        this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this));
        this.targetSelector.addGoal(3, new HurtByTargetGoal(this, new Class[0]).setAlertOthers(new Class[0]));
        this.targetSelector.addGoal(4, new NonTameRandomTargetGoal<>(this, Animal.class, false, Wolf.PREY_SELECTOR));
        this.targetSelector.addGoal(4, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR));
        this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, AbstractSkeleton.class, false));
    }
    
    @Override
    protected void registerAttributes() {
        super.registerAttributes();
        this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.30000001192092896);
        if (this.isTame()) {
            this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(20.0);
        }
        else {
            this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(8.0);
        }
        this.getAttributes().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(2.0);
    }
    
    @Override
    public void setTarget(@Nullable final LivingEntity akz) {
        super.setTarget(akz);
        if (akz == null) {
            this.setAngry(false);
        }
        else if (!this.isTame()) {
            this.setAngry(true);
        }
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Boolean>define(Wolf.DATA_INTERESTED_ID, false);
        this.entityData.<Integer>define(Wolf.DATA_COLLAR_COLOR, DyeColor.RED.getId());
    }
    
    @Override
    protected void playStepSound(final BlockPos fk, final BlockState byj) {
        this.playSound(SoundEvents.WOLF_STEP, 0.15f, 1.0f);
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag jt) {
        super.addAdditionalSaveData(jt);
        jt.putBoolean("Angry", this.isAngry());
        jt.putByte("CollarColor", (byte)this.getCollarColor().getId());
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        super.readAdditionalSaveData(jt);
        this.setAngry(jt.getBoolean("Angry"));
        if (jt.contains("CollarColor", 99)) {
            this.setCollarColor(DyeColor.byId(jt.getInt("CollarColor")));
        }
    }
    
    @Override
    protected SoundEvent getAmbientSound() {
        if (this.isAngry()) {
            return SoundEvents.WOLF_GROWL;
        }
        if (this.random.nextInt(3) != 0) {
            return SoundEvents.WOLF_AMBIENT;
        }
        if (this.isTame() && this.getHealth() < 10.0f) {
            return SoundEvents.WOLF_WHINE;
        }
        return SoundEvents.WOLF_PANT;
    }
    
    @Override
    protected SoundEvent getHurtSound(final DamageSource ajz) {
        return SoundEvents.WOLF_HURT;
    }
    
    @Override
    protected SoundEvent getDeathSound() {
        return SoundEvents.WOLF_DEATH;
    }
    
    @Override
    protected float getSoundVolume() {
        return 0.4f;
    }
    
    @Override
    public void aiStep() {
        super.aiStep();
        if (!this.level.isClientSide && this.isWet && !this.isShaking && !this.isPathFinding() && this.onGround) {
            this.isShaking = true;
            this.shakeAnim = 0.0f;
            this.shakeAnimO = 0.0f;
            this.level.broadcastEntityEvent(this, (byte)8);
        }
        if (!this.level.isClientSide && this.getTarget() == null && this.isAngry()) {
            this.setAngry(false);
        }
    }
    
    @Override
    public void tick() {
        super.tick();
        if (!this.isAlive()) {
            return;
        }
        this.interestedAngleO = this.interestedAngle;
        if (this.isInterested()) {
            this.interestedAngle += (1.0f - this.interestedAngle) * 0.4f;
        }
        else {
            this.interestedAngle += (0.0f - this.interestedAngle) * 0.4f;
        }
        if (this.isInWaterRainOrBubble()) {
            this.isWet = true;
            this.isShaking = false;
            this.shakeAnim = 0.0f;
            this.shakeAnimO = 0.0f;
        }
        else if ((this.isWet || this.isShaking) && this.isShaking) {
            if (this.shakeAnim == 0.0f) {
                this.playSound(SoundEvents.WOLF_SHAKE, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2f + 1.0f);
            }
            this.shakeAnimO = this.shakeAnim;
            this.shakeAnim += 0.05f;
            if (this.shakeAnimO >= 2.0f) {
                this.isWet = false;
                this.isShaking = false;
                this.shakeAnimO = 0.0f;
                this.shakeAnim = 0.0f;
            }
            if (this.shakeAnim > 0.4f) {
                final float float2 = (float)this.getY();
                final int integer3 = (int)(Mth.sin((this.shakeAnim - 0.4f) * 3.1415927f) * 7.0f);
                final Vec3 cvl4 = this.getDeltaMovement();
                for (int integer4 = 0; integer4 < integer3; ++integer4) {
                    final float float3 = (this.random.nextFloat() * 2.0f - 1.0f) * this.getBbWidth() * 0.5f;
                    final float float4 = (this.random.nextFloat() * 2.0f - 1.0f) * this.getBbWidth() * 0.5f;
                    this.level.addParticle(ParticleTypes.SPLASH, this.getX() + float3, float2 + 0.8f, this.getZ() + float4, cvl4.x, cvl4.y, cvl4.z);
                }
            }
        }
    }
    
    @Override
    public void die(final DamageSource ajz) {
        this.isWet = false;
        this.isShaking = false;
        this.shakeAnimO = 0.0f;
        this.shakeAnim = 0.0f;
        super.die(ajz);
    }
    
    public boolean isWet() {
        return this.isWet;
    }
    
    public float getWetShade(final float float1) {
        return 0.75f + Mth.lerp(float1, this.shakeAnimO, this.shakeAnim) / 2.0f * 0.25f;
    }
    
    public float getBodyRollAngle(final float float1, final float float2) {
        float float3 = (Mth.lerp(float1, this.shakeAnimO, this.shakeAnim) + float2) / 1.8f;
        if (float3 < 0.0f) {
            float3 = 0.0f;
        }
        else if (float3 > 1.0f) {
            float3 = 1.0f;
        }
        return Mth.sin(float3 * 3.1415927f) * Mth.sin(float3 * 3.1415927f * 11.0f) * 0.15f * 3.1415927f;
    }
    
    public float getHeadRollAngle(final float float1) {
        return Mth.lerp(float1, this.interestedAngleO, this.interestedAngle) * 0.15f * 3.1415927f;
    }
    
    @Override
    protected float getStandingEyeHeight(final Pose alj, final EntityDimensions akr) {
        return akr.height * 0.8f;
    }
    
    @Override
    public int getMaxHeadXRot() {
        if (this.isSitting()) {
            return 20;
        }
        return super.getMaxHeadXRot();
    }
    
    @Override
    public boolean hurt(final DamageSource ajz, float float2) {
        if (this.isInvulnerableTo(ajz)) {
            return false;
        }
        final Entity akq4 = ajz.getEntity();
        if (this.sitGoal != null) {
            this.sitGoal.wantToSit(false);
        }
        if (akq4 != null && !(akq4 instanceof Player) && !(akq4 instanceof AbstractArrow)) {
            float2 = (float2 + 1.0f) / 2.0f;
        }
        return super.hurt(ajz, float2);
    }
    
    @Override
    public boolean doHurtTarget(final Entity akq) {
        final boolean boolean3 = akq.hurt(DamageSource.mobAttack(this), (float)(int)this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getValue());
        if (boolean3) {
            this.doEnchantDamageEffects(this, akq);
        }
        return boolean3;
    }
    
    @Override
    public void setTame(final boolean boolean1) {
        super.setTame(boolean1);
        if (boolean1) {
            this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(20.0);
            this.setHealth(20.0f);
        }
        else {
            this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(8.0);
        }
        this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(4.0);
    }
    
    @Override
    public boolean mobInteract(final Player ayj, final InteractionHand ajk) {
        final ItemStack ben4 = ayj.getItemInHand(ajk);
        final Item bei5 = ben4.getItem();
        if (ben4.getItem() instanceof SpawnEggItem) {
            return super.mobInteract(ayj, ajk);
        }
        if (this.level.isClientSide) {
            return this.isOwnedBy(ayj) || (bei5 == Items.BONE && !this.isAngry());
        }
        if (this.isTame()) {
            if (bei5.isEdible() && bei5.getFoodProperties().isMeat() && this.getHealth() < this.getMaxHealth()) {
                if (!ayj.abilities.instabuild) {
                    ben4.shrink(1);
                }
                this.heal((float)bei5.getFoodProperties().getNutrition());
                return true;
            }
            if (!(bei5 instanceof DyeItem)) {
                final boolean boolean6 = super.mobInteract(ayj, ajk);
                if (!boolean6 || this.isBaby()) {
                    this.sitGoal.wantToSit(!this.isSitting());
                }
                return boolean6;
            }
            final DyeColor bdj6 = ((DyeItem)bei5).getDyeColor();
            if (bdj6 != this.getCollarColor()) {
                this.setCollarColor(bdj6);
                if (!ayj.abilities.instabuild) {
                    ben4.shrink(1);
                }
                return true;
            }
            if (this.isOwnedBy(ayj) && !this.isFood(ben4)) {
                this.sitGoal.wantToSit(!this.isSitting());
                this.jumping = false;
                this.navigation.stop();
                this.setTarget(null);
            }
        }
        else if (bei5 == Items.BONE && !this.isAngry()) {
            if (!ayj.abilities.instabuild) {
                ben4.shrink(1);
            }
            if (this.random.nextInt(3) == 0) {
                this.tame(ayj);
                this.navigation.stop();
                this.setTarget(null);
                this.sitGoal.wantToSit(true);
                this.level.broadcastEntityEvent(this, (byte)7);
            }
            else {
                this.level.broadcastEntityEvent(this, (byte)6);
            }
            return true;
        }
        return super.mobInteract(ayj, ajk);
    }
    
    @Override
    public void handleEntityEvent(final byte byte1) {
        if (byte1 == 8) {
            this.isShaking = true;
            this.shakeAnim = 0.0f;
            this.shakeAnimO = 0.0f;
        }
        else {
            super.handleEntityEvent(byte1);
        }
    }
    
    public float getTailAngle() {
        if (this.isAngry()) {
            return 1.5393804f;
        }
        if (this.isTame()) {
            return (0.55f - (this.getMaxHealth() - this.getHealth()) * 0.02f) * 3.1415927f;
        }
        return 0.62831855f;
    }
    
    @Override
    public boolean isFood(final ItemStack ben) {
        final Item bei3 = ben.getItem();
        return bei3.isEdible() && bei3.getFoodProperties().isMeat();
    }
    
    @Override
    public int getMaxSpawnClusterSize() {
        return 8;
    }
    
    public boolean isAngry() {
        return (this.entityData.<Byte>get(Wolf.DATA_FLAGS_ID) & 0x2) != 0x0;
    }
    
    public void setAngry(final boolean boolean1) {
        final byte byte3 = this.entityData.<Byte>get(Wolf.DATA_FLAGS_ID);
        if (boolean1) {
            this.entityData.<Byte>set(Wolf.DATA_FLAGS_ID, (byte)(byte3 | 0x2));
        }
        else {
            this.entityData.<Byte>set(Wolf.DATA_FLAGS_ID, (byte)(byte3 & 0xFFFFFFFD));
        }
    }
    
    public DyeColor getCollarColor() {
        return DyeColor.byId(this.entityData.<Integer>get(Wolf.DATA_COLLAR_COLOR));
    }
    
    public void setCollarColor(final DyeColor bdj) {
        this.entityData.<Integer>set(Wolf.DATA_COLLAR_COLOR, bdj.getId());
    }
    
    @Override
    public Wolf getBreedOffspring(final AgableMob ako) {
        final Wolf auc3 = EntityType.WOLF.create(this.level);
        final UUID uUID4 = this.getOwnerUUID();
        if (uUID4 != null) {
            auc3.setOwnerUUID(uUID4);
            auc3.setTame(true);
        }
        return auc3;
    }
    
    public void setIsInterested(final boolean boolean1) {
        this.entityData.<Boolean>set(Wolf.DATA_INTERESTED_ID, boolean1);
    }
    
    @Override
    public boolean canMate(final Animal atc) {
        if (atc == this) {
            return false;
        }
        if (!this.isTame()) {
            return false;
        }
        if (!(atc instanceof Wolf)) {
            return false;
        }
        final Wolf auc3 = (Wolf)atc;
        return auc3.isTame() && !auc3.isSitting() && this.isInLove() && auc3.isInLove();
    }
    
    public boolean isInterested() {
        return this.entityData.<Boolean>get(Wolf.DATA_INTERESTED_ID);
    }
    
    @Override
    public boolean wantsToAttack(final LivingEntity akz1, final LivingEntity akz2) {
        if (akz1 instanceof Creeper || akz1 instanceof Ghast) {
            return false;
        }
        if (akz1 instanceof Wolf) {
            final Wolf auc4 = (Wolf)akz1;
            return !auc4.isTame() || auc4.getOwner() != akz2;
        }
        return (!(akz1 instanceof Player) || !(akz2 instanceof Player) || ((Player)akz2).canHarmPlayer((Player)akz1)) && (!(akz1 instanceof AbstractHorse) || !((AbstractHorse)akz1).isTamed()) && (!(akz1 instanceof TamableAnimal) || !((TamableAnimal)akz1).isTame());
    }
    
    @Override
    public boolean canBeLeashed(final Player ayj) {
        return !this.isAngry() && super.canBeLeashed(ayj);
    }
    
    static {
        DATA_INTERESTED_ID = SynchedEntityData.<Boolean>defineId(Wolf.class, EntityDataSerializers.BOOLEAN);
        DATA_COLLAR_COLOR = SynchedEntityData.<Integer>defineId(Wolf.class, EntityDataSerializers.INT);
        final EntityType<?> aku2;
        PREY_SELECTOR = (akz -> {
            aku2 = akz.getType();
            return aku2 == EntityType.SHEEP || aku2 == EntityType.RABBIT || aku2 == EntityType.FOX;
        });
    }
    
    class WolfAvoidEntityGoal<T extends LivingEntity> extends AvoidEntityGoal<T> {
        private final Wolf wolf;
        
        public WolfAvoidEntityGoal(final Wolf auc2, final Class<T> class3, final float float4, final double double5, final double double6) {
            super(auc2, class3, float4, double5, double6);
            this.wolf = auc2;
        }
        
        @Override
        public boolean canUse() {
            return super.canUse() && this.toAvoid instanceof Llama && !this.wolf.isTame() && this.avoidLlama((Llama)this.toAvoid);
        }
        
        private boolean avoidLlama(final Llama auh) {
            return auh.getStrength() >= Wolf.this.random.nextInt(5);
        }
        
        @Override
        public void start() {
            Wolf.this.setTarget(null);
            super.start();
        }
        
        @Override
        public void tick() {
            Wolf.this.setTarget(null);
            super.tick();
        }
    }
}
