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.EntityHitResult;
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 javax.annotation.Nullable;
import net.minecraft.world.entity.Entity;
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;

public class FireworkRocketEntity extends Projectile implements ItemSupplier {
    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> aoq, final Level bqb) {
        super(aoq, bqb);
    }
    
    public FireworkRocketEntity(final Level bqb, final double double2, final double double3, final double double4, final ItemStack bki) {
        super(EntityType.FIREWORK_ROCKET, bqb);
        this.life = 0;
        this.setPos(double2, double3, double4);
        int integer10 = 1;
        if (!bki.isEmpty() && bki.hasTag()) {
            this.entityData.<ItemStack>set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, bki.copy());
            integer10 += bki.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 bqb, @Nullable final Entity aom, final double double3, final double double4, final double double5, final ItemStack bki) {
        this(bqb, double3, double4, double5, bki);
        this.setOwner(aom);
    }
    
    public FireworkRocketEntity(final Level bqb, final ItemStack bki, final LivingEntity aoy) {
        this(bqb, aoy, aoy.getX(), aoy.getY(), aoy.getZ(), bki);
        this.entityData.<OptionalInt>set(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET, OptionalInt.of(aoy.getId()));
        this.attachedToEntity = aoy;
    }
    
    public FireworkRocketEntity(final Level bqb, final ItemStack bki, final double double3, final double double4, final double double5, final boolean boolean6) {
        this(bqb, double3, double4, double5, bki);
        this.entityData.<Boolean>set(FireworkRocketEntity.DATA_SHOT_AT_ANGLE, boolean6);
    }
    
    public FireworkRocketEntity(final Level bqb, final ItemStack bki, final Entity aom, final double double4, final double double5, final double double6, final boolean boolean7) {
        this(bqb, bki, double4, double5, double6, boolean7);
        this.setOwner(aom);
    }
    
    @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();
    }
    
    @Override
    public void tick() {
        super.tick();
        if (this.isAttachedToEntity()) {
            if (this.attachedToEntity == null) {
                final Entity aom3;
                this.entityData.<OptionalInt>get(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET).ifPresent(integer -> {
                    aom3 = this.level.getEntity(integer);
                    if (aom3 instanceof LivingEntity) {
                        this.attachedToEntity = (LivingEntity)aom3;
                    }
                    return;
                });
            }
            if (this.attachedToEntity != null) {
                if (this.attachedToEntity.isFallFlying()) {
                    final Vec3 dem2 = this.attachedToEntity.getLookAngle();
                    final double double3 = 1.5;
                    final double double4 = 0.1;
                    final Vec3 dem3 = this.attachedToEntity.getDeltaMovement();
                    this.attachedToEntity.setDeltaMovement(dem3.add(dem2.x * 0.1 + (dem2.x * 1.5 - dem3.x) * 0.5, dem2.y * 0.1 + (dem2.y * 1.5 - dem3.y) * 0.5, dem2.z * 0.1 + (dem2.z * 1.5 - dem3.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));
            }
            final Vec3 dem2 = this.getDeltaMovement();
            this.move(MoverType.SELF, dem2);
            this.setDeltaMovement(dem2);
        }
        final HitResult dej2 = ProjectileUtil.getHitResult(this, this::canHitEntity, ClipContext.Block.COLLIDER);
        if (!this.noPhysics) {
            this.onHit(dej2);
            this.hasImpulse = true;
        }
        this.updateRotation();
        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();
    }
    
    @Override
    protected void onHitEntity(final EntityHitResult dei) {
        super.onHitEntity(dei);
        if (this.level.isClientSide) {
            return;
        }
        this.explode();
    }
    
    @Override
    protected void onHitBlock(final BlockHitResult deh) {
        final BlockPos fu3 = new BlockPos(deh.getBlockPos());
        this.level.getBlockState(fu3).entityInside(this.level, fu3, this);
        if (!this.level.isClientSide() && this.hasExplosion()) {
            this.explode();
        }
        super.onHitBlock(deh);
    }
    
    private boolean hasExplosion() {
        final ItemStack bki2 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
        final CompoundTag le3 = bki2.isEmpty() ? null : bki2.getTagElement("Fireworks");
        final ListTag lk4 = (le3 != null) ? le3.getList("Explosions", 10) : null;
        return lk4 != null && !lk4.isEmpty();
    }
    
    private void dealExplosionDamage() {
        float float2 = 0.0f;
        final ItemStack bki3 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
        final CompoundTag le4 = bki3.isEmpty() ? null : bki3.getTagElement("Fireworks");
        final ListTag lk5 = (le4 != null) ? le4.getList("Explosions", 10) : null;
        if (lk5 != null && !lk5.isEmpty()) {
            float2 = 5.0f + lk5.size() * 2;
        }
        if (float2 > 0.0f) {
            if (this.attachedToEntity != null) {
                this.attachedToEntity.hurt(DamageSource.fireworks(this, this.getOwner()), 5.0f + lk5.size() * 2);
            }
            final double double6 = 5.0;
            final Vec3 dem8 = this.position();
            final List<LivingEntity> list9 = this.level.<LivingEntity>getEntitiesOfClass(LivingEntity.class, this.getBoundingBox().inflate(5.0));
            for (final LivingEntity aoy11 : list9) {
                if (aoy11 == this.attachedToEntity) {
                    continue;
                }
                if (this.distanceToSqr(aoy11) > 25.0) {
                    continue;
                }
                boolean boolean12 = false;
                for (int integer13 = 0; integer13 < 2; ++integer13) {
                    final Vec3 dem9 = new Vec3(aoy11.getX(), aoy11.getY(0.5 * integer13), aoy11.getZ());
                    final HitResult dej15 = this.level.clip(new ClipContext(dem8, dem9, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this));
                    if (dej15.getType() == HitResult.Type.MISS) {
                        boolean12 = true;
                        break;
                    }
                }
                if (!boolean12) {
                    continue;
                }
                final float float3 = float2 * (float)Math.sqrt((5.0 - this.distanceTo(aoy11)) / 5.0);
                aoy11.hurt(DamageSource.fireworks(this, this.getOwner()), 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 bki3 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
                final CompoundTag le4 = bki3.isEmpty() ? null : bki3.getTagElement("Fireworks");
                final Vec3 dem5 = this.getDeltaMovement();
                this.level.createFireworks(this.getX(), this.getY(), this.getZ(), dem5.x, dem5.y, dem5.z, le4);
            }
        }
        super.handleEntityEvent(byte1);
    }
    
    public void addAdditionalSaveData(final CompoundTag le) {
        super.addAdditionalSaveData(le);
        le.putInt("Life", this.life);
        le.putInt("LifeTime", this.lifetime);
        final ItemStack bki3 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
        if (!bki3.isEmpty()) {
            le.put("FireworksItem", bki3.save(new CompoundTag()));
        }
        le.putBoolean("ShotAtAngle", this.entityData.<Boolean>get(FireworkRocketEntity.DATA_SHOT_AT_ANGLE));
    }
    
    public void readAdditionalSaveData(final CompoundTag le) {
        super.readAdditionalSaveData(le);
        this.life = le.getInt("Life");
        this.lifetime = le.getInt("LifeTime");
        final ItemStack bki3 = ItemStack.of(le.getCompound("FireworksItem"));
        if (!bki3.isEmpty()) {
            this.entityData.<ItemStack>set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, bki3);
        }
        if (le.contains("ShotAtAngle")) {
            this.entityData.<Boolean>set(FireworkRocketEntity.DATA_SHOT_AT_ANGLE, le.getBoolean("ShotAtAngle"));
        }
    }
    
    @Override
    public ItemStack getItem() {
        final ItemStack bki2 = this.entityData.<ItemStack>get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
        return bki2.isEmpty() ? new ItemStack(Items.FIREWORK_ROCKET) : bki2;
    }
    
    @Override
    public boolean isAttackable() {
        return false;
    }
    
    @Override
    public Packet<?> getAddEntityPacket() {
        return new ClientboundAddEntityPacket(this);
    }
    
    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);
    }
}
