package net.minecraft.world.entity.projectile;

import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.network.protocol.Packet;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.Items;
import net.minecraft.nbt.Tag;
import java.util.Iterator;
import java.util.List;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.core.Vec3i;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.sounds.SoundSource;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.entity.MoverType;
import net.minecraft.util.Mth;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import java.util.OptionalInt;
import net.minecraft.world.item.ItemStack;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.Entity;

public class FireworkRocketEntity extends Entity implements ItemSupplier, Projectile {
    private static final EntityDataAccessor<ItemStack> DATA_ID_FIREWORKS_ITEM;
    private static final EntityDataAccessor<OptionalInt> DATA_ATTACHED_TO_TARGET;
    private static final EntityDataAccessor<Boolean> DATA_SHOT_AT_ANGLE;
    private int life;
    private int lifetime;
    private LivingEntity attachedToEntity;
    
    public FireworkRocketEntity(final EntityType<? extends FireworkRocketEntity> aku, final Level bjw) {
        super(aku, bjw);
    }
    
    @Override
    protected void defineSynchedData() {
        this.entityData.<ItemStack>define(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, ItemStack.EMPTY);
        this.entityData.<OptionalInt>define(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET, OptionalInt.empty());
        this.entityData.<Boolean>define(FireworkRocketEntity.DATA_SHOT_AT_ANGLE, false);
    }
    
    @Override
    public boolean shouldRenderAtSqrDistance(final double double1) {
        return double1 < 4096.0 && !this.isAttachedToEntity();
    }
    
    @Override
    public boolean shouldRender(final double double1, final double double2, final double double3) {
        return super.shouldRender(double1, double2, double3) && !this.isAttachedToEntity();
    }
    
    public FireworkRocketEntity(final Level bjw, final double double2, final double double3, final double double4, final ItemStack ben) {
        super(EntityType.FIREWORK_ROCKET, bjw);
        this.life = 0;
        this.setPos(double2, double3, double4);
        int integer10 = 1;
        if (!ben.isEmpty() && ben.hasTag()) {
            this.entityData.<ItemStack>set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, ben.copy());
            integer10 += ben.getOrCreateTagElement("Fireworks").getByte("Flight");
        }
        this.setDeltaMovement(this.random.nextGaussian() * 0.001, 0.05, this.random.nextGaussian() * 0.001);
        this.lifetime = 10 * integer10 + this.random.nextInt(6) + this.random.nextInt(7);
    }
    
    public FireworkRocketEntity(final Level bjw, final ItemStack ben, final LivingEntity akz) {
        this(bjw, akz.getX(), akz.getY(), akz.getZ(), ben);
        this.entityData.<OptionalInt>set(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET, OptionalInt.of(akz.getId()));
        this.attachedToEntity = akz;
    }
    
    public FireworkRocketEntity(final Level bjw, final ItemStack ben, final double double3, final double double4, final double double5, final boolean boolean6) {
        this(bjw, double3, double4, double5, ben);
        this.entityData.<Boolean>set(FireworkRocketEntity.DATA_SHOT_AT_ANGLE, boolean6);
    }
    
    @Override
    public void lerpMotion(final double double1, final double double2, final double double3) {
        this.setDeltaMovement(double1, double2, double3);
        if (this.xRotO == 0.0f && this.yRotO == 0.0f) {
            final float float8 = Mth.sqrt(double1 * double1 + double3 * double3);
            this.yRot = (float)(Mth.atan2(double1, double3) * 57.2957763671875);
            this.xRot = (float)(Mth.atan2(double2, float8) * 57.2957763671875);
            this.yRotO = this.yRot;
            this.xRotO = this.xRot;
        }
    }
    
    @Override
    public void tick() {
        super.tick();
        if (this.isAttachedToEntity()) {
            if (this.attachedToEntity == null) {
                final Entity akq2;
                this.entityData.<OptionalInt>get(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET).ifPresent(integer -> {
                    akq2 = this.level.getEntity(integer);
                    if (akq2 instanceof LivingEntity) {
                        this.attachedToEntity = (LivingEntity)akq2;
                    }
                    return;
                });
            }
            if (this.attachedToEntity != null) {
                if (this.attachedToEntity.isFallFlying()) {
                    final Vec3 cvl2 = this.attachedToEntity.getLookAngle();
                    final double double3 = 1.5;
                    final double double4 = 0.1;
                    final Vec3 cvl3 = this.attachedToEntity.getDeltaMovement();
                    this.attachedToEntity.setDeltaMovement(cvl3.add(cvl2.x * 0.1 + (cvl2.x * 1.5 - cvl3.x) * 0.5, cvl2.y * 0.1 + (cvl2.y * 1.5 - cvl3.y) * 0.5, cvl2.z * 0.1 + (cvl2.z * 1.5 - cvl3.z) * 0.5));
                }
                this.setPos(this.attachedToEntity.getX(), this.attachedToEntity.getY(), this.attachedToEntity.getZ());
                this.setDeltaMovement(this.attachedToEntity.getDeltaMovement());
            }
        }
        else {
            if (!this.isShotAtAngle()) {
                this.setDeltaMovement(this.getDeltaMovement().multiply(1.15, 1.0, 1.15).add(0.0, 0.04, 0.0));
            }
            this.move(MoverType.SELF, this.getDeltaMovement());
        }
        final Vec3 cvl2 = this.getDeltaMovement();
        final HitResult cvi3 = ProjectileUtil.getHitResult(this, this.getBoundingBox().expandTowards(cvl2).inflate(1.0), akq -> !akq.isSpectator() && akq.isAlive() && akq.isPickable(), ClipContext.Block.COLLIDER, true);
        if (!this.noPhysics) {
            this.performHitChecks(cvi3);
            this.hasImpulse = true;
        }
        final float float4 = Mth.sqrt(Entity.getHorizontalDistanceSqr(cvl2));
        this.yRot = (float)(Mth.atan2(cvl2.x, cvl2.z) * 57.2957763671875);
        this.xRot = (float)(Mth.atan2(cvl2.y, float4) * 57.2957763671875);
        while (this.xRot - this.xRotO < -180.0f) {
            this.xRotO -= 360.0f;
        }
        while (this.xRot - this.xRotO >= 180.0f) {
            this.xRotO += 360.0f;
        }
        while (this.yRot - this.yRotO < -180.0f) {
            this.yRotO -= 360.0f;
        }
        while (this.yRot - this.yRotO >= 180.0f) {
            this.yRotO += 360.0f;
        }
        this.xRot = Mth.lerp(0.2f, this.xRotO, this.xRot);
        this.yRot = Mth.lerp(0.2f, this.yRotO, this.yRot);
        if (this.life == 0 && !this.isSilent()) {
            this.level.playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.FIREWORK_ROCKET_LAUNCH, SoundSource.AMBIENT, 3.0f, 1.0f);
        }
        ++this.life;
        if (this.level.isClientSide && this.life % 2 < 2) {
            this.level.addParticle(ParticleTypes.FIREWORK, this.getX(), this.getY() - 0.3, this.getZ(), this.random.nextGaussian() * 0.05, -this.getDeltaMovement().y * 0.5, this.random.nextGaussian() * 0.05);
        }
        if (!this.level.isClientSide && this.life > this.lifetime) {
            this.explode();
        }
    }
    
    private void explode() {
        this.level.broadcastEntityEvent(this, (byte)17);
        this.dealExplosionDamage();
        this.remove();
    }
    
    protected void performHitChecks(final HitResult cvi) {
        if (cvi.getType() == HitResult.Type.ENTITY && !this.level.isClientSide) {
            this.explode();
        }
        else if (this.collision) {
            BlockPos fk3;
            if (cvi.getType() == HitResult.Type.BLOCK) {
                fk3 = new BlockPos(((BlockHitResult)cvi).getBlockPos());
            }
            else {
                fk3 = new BlockPos(this);
            }
            this.level.getBlockState(fk3).entityInside(this.level, fk3, this);
            if (this.hasExplosion()) {
                this.explode();
            }
        }
    }
    
    private boolean hasExplosion() {
        final ItemStack ben2 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
        final CompoundTag jt3 = ben2.isEmpty() ? null : ben2.getTagElement("Fireworks");
        final ListTag jz4 = (jt3 != null) ? jt3.getList("Explosions", 10) : null;
        return jz4 != null && !jz4.isEmpty();
    }
    
    private void dealExplosionDamage() {
        float float2 = 0.0f;
        final ItemStack ben3 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
        final CompoundTag jt4 = ben3.isEmpty() ? null : ben3.getTagElement("Fireworks");
        final ListTag jz5 = (jt4 != null) ? jt4.getList("Explosions", 10) : null;
        if (jz5 != null && !jz5.isEmpty()) {
            float2 = 5.0f + jz5.size() * 2;
        }
        if (float2 > 0.0f) {
            if (this.attachedToEntity != null) {
                this.attachedToEntity.hurt(DamageSource.FIREWORKS, 5.0f + jz5.size() * 2);
            }
            final double double6 = 5.0;
            final Vec3 cvl8 = this.position();
            final List<LivingEntity> list9 = this.level.<LivingEntity>getEntitiesOfClass(LivingEntity.class, this.getBoundingBox().inflate(5.0));
            for (final LivingEntity akz11 : list9) {
                if (akz11 == this.attachedToEntity) {
                    continue;
                }
                if (this.distanceToSqr(akz11) > 25.0) {
                    continue;
                }
                boolean boolean12 = false;
                for (int integer13 = 0; integer13 < 2; ++integer13) {
                    final Vec3 cvl9 = new Vec3(akz11.getX(), akz11.getY(0.5 * integer13), akz11.getZ());
                    final HitResult cvi15 = this.level.clip(new ClipContext(cvl8, cvl9, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this));
                    if (cvi15.getType() == HitResult.Type.MISS) {
                        boolean12 = true;
                        break;
                    }
                }
                if (!boolean12) {
                    continue;
                }
                final float float3 = float2 * (float)Math.sqrt((5.0 - this.distanceTo(akz11)) / 5.0);
                akz11.hurt(DamageSource.FIREWORKS, float3);
            }
        }
    }
    
    private boolean isAttachedToEntity() {
        return this.entityData.<OptionalInt>get(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET).isPresent();
    }
    
    public boolean isShotAtAngle() {
        return this.entityData.<Boolean>get(FireworkRocketEntity.DATA_SHOT_AT_ANGLE);
    }
    
    @Override
    public void handleEntityEvent(final byte byte1) {
        if (byte1 == 17 && this.level.isClientSide) {
            if (!this.hasExplosion()) {
                for (int integer3 = 0; integer3 < this.random.nextInt(3) + 2; ++integer3) {
                    this.level.addParticle(ParticleTypes.POOF, this.getX(), this.getY(), this.getZ(), this.random.nextGaussian() * 0.05, 0.005, this.random.nextGaussian() * 0.05);
                }
            }
            else {
                final ItemStack ben3 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
                final CompoundTag jt4 = ben3.isEmpty() ? null : ben3.getTagElement("Fireworks");
                final Vec3 cvl5 = this.getDeltaMovement();
                this.level.createFireworks(this.getX(), this.getY(), this.getZ(), cvl5.x, cvl5.y, cvl5.z, jt4);
            }
        }
        super.handleEntityEvent(byte1);
    }
    
    public void addAdditionalSaveData(final CompoundTag jt) {
        jt.putInt("Life", this.life);
        jt.putInt("LifeTime", this.lifetime);
        final ItemStack ben3 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
        if (!ben3.isEmpty()) {
            jt.put("FireworksItem", ben3.save(new CompoundTag()));
        }
        jt.putBoolean("ShotAtAngle", this.entityData.<Boolean>get(FireworkRocketEntity.DATA_SHOT_AT_ANGLE));
    }
    
    public void readAdditionalSaveData(final CompoundTag jt) {
        this.life = jt.getInt("Life");
        this.lifetime = jt.getInt("LifeTime");
        final ItemStack ben3 = ItemStack.of(jt.getCompound("FireworksItem"));
        if (!ben3.isEmpty()) {
            this.entityData.<ItemStack>set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, ben3);
        }
        if (jt.contains("ShotAtAngle")) {
            this.entityData.<Boolean>set(FireworkRocketEntity.DATA_SHOT_AT_ANGLE, jt.getBoolean("ShotAtAngle"));
        }
    }
    
    @Override
    public ItemStack getItem() {
        final ItemStack ben2 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
        return ben2.isEmpty() ? new ItemStack(Items.FIREWORK_ROCKET) : ben2;
    }
    
    @Override
    public boolean isAttackable() {
        return false;
    }
    
    @Override
    public Packet<?> getAddEntityPacket() {
        return new ClientboundAddEntityPacket(this);
    }
    
    @Override
    public void shoot(double double1, double double2, double double3, final float float4, final float float5) {
        final float float6 = Mth.sqrt(double1 * double1 + double2 * double2 + double3 * double3);
        double1 /= float6;
        double2 /= float6;
        double3 /= float6;
        double1 += this.random.nextGaussian() * 0.007499999832361937 * float5;
        double2 += this.random.nextGaussian() * 0.007499999832361937 * float5;
        double3 += this.random.nextGaussian() * 0.007499999832361937 * float5;
        double1 *= float4;
        double2 *= float4;
        double3 *= float4;
        this.setDeltaMovement(double1, double2, double3);
    }
    
    static {
        DATA_ID_FIREWORKS_ITEM = SynchedEntityData.<ItemStack>defineId(FireworkRocketEntity.class, EntityDataSerializers.ITEM_STACK);
        DATA_ATTACHED_TO_TARGET = SynchedEntityData.<OptionalInt>defineId(FireworkRocketEntity.class, EntityDataSerializers.OPTIONAL_UNSIGNED_INT);
        DATA_SHOT_AT_ANGLE = SynchedEntityData.<Boolean>defineId(FireworkRocketEntity.class, EntityDataSerializers.BOOLEAN);
    }
}
