package net.minecraft.world.entity.monster;

import java.util.EnumSet;
import net.minecraft.world.phys.AABB;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.entity.ai.control.MoveControl;
import net.minecraft.world.entity.Entity;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Pose;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.Difficulty;
import java.util.Random;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.projectile.LargeFireball;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.FlyingMob;

public class Ghast extends FlyingMob implements Enemy {
    private static final EntityDataAccessor<Boolean> DATA_IS_CHARGING;
    private int explosionPower;
    
    public Ghast(final EntityType<? extends Ghast> aku, final Level bjw) {
        super(aku, bjw);
        this.explosionPower = 1;
        this.xpReward = 5;
        this.moveControl = new GhastMoveControl(this);
    }
    
    @Override
    protected void registerGoals() {
        this.goalSelector.addGoal(5, new RandomFloatAroundGoal(this));
        this.goalSelector.addGoal(7, new GhastLookGoal(this));
        this.goalSelector.addGoal(7, new GhastShootFireballGoal(this));
        this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, akz -> Math.abs(akz.getY() - this.getY()) <= 4.0));
    }
    
    public boolean isCharging() {
        return this.entityData.<Boolean>get(Ghast.DATA_IS_CHARGING);
    }
    
    public void setCharging(final boolean boolean1) {
        this.entityData.<Boolean>set(Ghast.DATA_IS_CHARGING, boolean1);
    }
    
    public int getExplosionPower() {
        return this.explosionPower;
    }
    
    @Override
    protected boolean shouldDespawnInPeaceful() {
        return true;
    }
    
    @Override
    public boolean hurt(final DamageSource ajz, final float float2) {
        if (this.isInvulnerableTo(ajz)) {
            return false;
        }
        if (ajz.getDirectEntity() instanceof LargeFireball && ajz.getEntity() instanceof Player) {
            super.hurt(ajz, 1000.0f);
            return true;
        }
        return super.hurt(ajz, float2);
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Boolean>define(Ghast.DATA_IS_CHARGING, false);
    }
    
    @Override
    protected void registerAttributes() {
        super.registerAttributes();
        this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(10.0);
        this.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(100.0);
    }
    
    @Override
    public SoundSource getSoundSource() {
        return SoundSource.HOSTILE;
    }
    
    @Override
    protected SoundEvent getAmbientSound() {
        return SoundEvents.GHAST_AMBIENT;
    }
    
    @Override
    protected SoundEvent getHurtSound(final DamageSource ajz) {
        return SoundEvents.GHAST_HURT;
    }
    
    @Override
    protected SoundEvent getDeathSound() {
        return SoundEvents.GHAST_DEATH;
    }
    
    @Override
    protected float getSoundVolume() {
        return 10.0f;
    }
    
    public static boolean checkGhastSpawnRules(final EntityType<Ghast> aku, final LevelAccessor bjx, final MobSpawnType alc, final BlockPos fk, final Random random) {
        return bjx.getDifficulty() != Difficulty.PEACEFUL && random.nextInt(20) == 0 && Mob.checkMobSpawnRules(aku, bjx, alc, fk, random);
    }
    
    @Override
    public int getMaxSpawnClusterSize() {
        return 1;
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag jt) {
        super.addAdditionalSaveData(jt);
        jt.putInt("ExplosionPower", this.explosionPower);
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        super.readAdditionalSaveData(jt);
        if (jt.contains("ExplosionPower", 99)) {
            this.explosionPower = jt.getInt("ExplosionPower");
        }
    }
    
    @Override
    protected float getStandingEyeHeight(final Pose alj, final EntityDimensions akr) {
        return 2.6f;
    }
    
    static {
        DATA_IS_CHARGING = SynchedEntityData.<Boolean>defineId(Ghast.class, EntityDataSerializers.BOOLEAN);
    }
    
    static class GhastMoveControl extends MoveControl {
        private final Ghast ghast;
        private int floatDuration;
        
        public GhastMoveControl(final Ghast awq) {
            super(awq);
            this.ghast = awq;
        }
        
        @Override
        public void tick() {
            if (this.operation != Operation.MOVE_TO) {
                return;
            }
            if (this.floatDuration-- <= 0) {
                this.floatDuration += this.ghast.getRandom().nextInt(5) + 2;
                Vec3 cvl2 = new Vec3(this.wantedX - this.ghast.getX(), this.wantedY - this.ghast.getY(), this.wantedZ - this.ghast.getZ());
                final double double3 = cvl2.length();
                cvl2 = cvl2.normalize();
                if (this.canReach(cvl2, Mth.ceil(double3))) {
                    this.ghast.setDeltaMovement(this.ghast.getDeltaMovement().add(cvl2.scale(0.1)));
                }
                else {
                    this.operation = Operation.WAIT;
                }
            }
        }
        
        private boolean canReach(final Vec3 cvl, final int integer) {
            AABB cvf4 = this.ghast.getBoundingBox();
            for (int integer2 = 1; integer2 < integer; ++integer2) {
                cvf4 = cvf4.move(cvl);
                if (!this.ghast.level.noCollision(this.ghast, cvf4)) {
                    return false;
                }
            }
            return true;
        }
    }
    
    static class RandomFloatAroundGoal extends Goal {
        private final Ghast ghast;
        
        public RandomFloatAroundGoal(final Ghast awq) {
            this.ghast = awq;
            this.setFlags(EnumSet.<Flag>of(Flag.MOVE));
        }
        
        @Override
        public boolean canUse() {
            final MoveControl aom2 = this.ghast.getMoveControl();
            if (!aom2.hasWanted()) {
                return true;
            }
            final double double3 = aom2.getWantedX() - this.ghast.getX();
            final double double4 = aom2.getWantedY() - this.ghast.getY();
            final double double5 = aom2.getWantedZ() - this.ghast.getZ();
            final double double6 = double3 * double3 + double4 * double4 + double5 * double5;
            return double6 < 1.0 || double6 > 3600.0;
        }
        
        @Override
        public boolean canContinueToUse() {
            return false;
        }
        
        @Override
        public void start() {
            final Random random2 = this.ghast.getRandom();
            final double double3 = this.ghast.getX() + (random2.nextFloat() * 2.0f - 1.0f) * 16.0f;
            final double double4 = this.ghast.getY() + (random2.nextFloat() * 2.0f - 1.0f) * 16.0f;
            final double double5 = this.ghast.getZ() + (random2.nextFloat() * 2.0f - 1.0f) * 16.0f;
            this.ghast.getMoveControl().setWantedPosition(double3, double4, double5, 1.0);
        }
    }
    
    static class GhastLookGoal extends Goal {
        private final Ghast ghast;
        
        public GhastLookGoal(final Ghast awq) {
            this.ghast = awq;
            this.setFlags(EnumSet.<Flag>of(Flag.LOOK));
        }
        
        @Override
        public boolean canUse() {
            return true;
        }
        
        @Override
        public void tick() {
            if (this.ghast.getTarget() == null) {
                final Vec3 cvl2 = this.ghast.getDeltaMovement();
                this.ghast.yRot = -(float)Mth.atan2(cvl2.x, cvl2.z) * 57.295776f;
                this.ghast.yBodyRot = this.ghast.yRot;
            }
            else {
                final LivingEntity akz2 = this.ghast.getTarget();
                final double double3 = 64.0;
                if (akz2.distanceToSqr(this.ghast) < 4096.0) {
                    final double double4 = akz2.getX() - this.ghast.getX();
                    final double double5 = akz2.getZ() - this.ghast.getZ();
                    this.ghast.yRot = -(float)Mth.atan2(double4, double5) * 57.295776f;
                    this.ghast.yBodyRot = this.ghast.yRot;
                }
            }
        }
    }
    
    static class GhastShootFireballGoal extends Goal {
        private final Ghast ghast;
        public int chargeTime;
        
        public GhastShootFireballGoal(final Ghast awq) {
            this.ghast = awq;
        }
        
        @Override
        public boolean canUse() {
            return this.ghast.getTarget() != null;
        }
        
        @Override
        public void start() {
            this.chargeTime = 0;
        }
        
        @Override
        public void stop() {
            this.ghast.setCharging(false);
        }
        
        @Override
        public void tick() {
            final LivingEntity akz2 = this.ghast.getTarget();
            final double double3 = 64.0;
            if (akz2.distanceToSqr(this.ghast) < 4096.0 && this.ghast.canSee(akz2)) {
                final Level bjw5 = this.ghast.level;
                ++this.chargeTime;
                if (this.chargeTime == 10) {
                    bjw5.levelEvent(null, 1015, new BlockPos(this.ghast), 0);
                }
                if (this.chargeTime == 20) {
                    final double double4 = 4.0;
                    final Vec3 cvl8 = this.ghast.getViewVector(1.0f);
                    final double double5 = akz2.getX() - (this.ghast.getX() + cvl8.x * 4.0);
                    final double double6 = akz2.getY(0.5) - (0.5 + this.ghast.getY(0.5));
                    final double double7 = akz2.getZ() - (this.ghast.getZ() + cvl8.z * 4.0);
                    bjw5.levelEvent(null, 1016, new BlockPos(this.ghast), 0);
                    final LargeFireball ayw15 = new LargeFireball(bjw5, this.ghast, double5, double6, double7);
                    ayw15.explosionPower = this.ghast.getExplosionPower();
                    ayw15.setPos(this.ghast.getX() + cvl8.x * 4.0, this.ghast.getY(0.5) + 0.5, ayw15.getZ() + cvl8.z * 4.0);
                    bjw5.addFreshEntity(ayw15);
                    this.chargeTime = -40;
                }
            }
            else if (this.chargeTime > 0) {
                --this.chargeTime;
            }
            this.ghast.setCharging(this.chargeTime > 10);
        }
    }
}
