package net.minecraft.world.entity.item;

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 javax.annotation.Nullable;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Item;
import net.minecraft.stats.Stat;
import net.minecraft.stats.Stats;
import net.minecraft.world.entity.player.Player;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Items;
import net.minecraft.world.damagesource.DamageSource;
import java.util.Objects;
import java.util.Iterator;
import java.util.List;
import net.minecraft.world.phys.Vec3;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.tags.Tag;
import net.minecraft.tags.FluidTags;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import java.util.UUID;
import net.minecraft.world.item.ItemStack;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.Entity;

public class ItemEntity extends Entity {
    private static final EntityDataAccessor<ItemStack> DATA_ITEM;
    private int age;
    private int pickupDelay;
    private int health;
    private UUID thrower;
    private UUID owner;
    public final float bobOffs;
    
    public ItemEntity(final EntityType<? extends ItemEntity> aoq, final Level bqb) {
        super(aoq, bqb);
        this.health = 5;
        this.bobOffs = (float)(Math.random() * 3.141592653589793 * 2.0);
    }
    
    public ItemEntity(final Level bqb, final double double2, final double double3, final double double4) {
        this(EntityType.ITEM, bqb);
        this.setPos(double2, double3, double4);
        this.yRot = this.random.nextFloat() * 360.0f;
        this.setDeltaMovement(this.random.nextDouble() * 0.2 - 0.1, 0.2, this.random.nextDouble() * 0.2 - 0.1);
    }
    
    public ItemEntity(final Level bqb, final double double2, final double double3, final double double4, final ItemStack bki) {
        this(bqb, double2, double3, double4);
        this.setItem(bki);
    }
    
    private ItemEntity(final ItemEntity bbg) {
        super(bbg.getType(), bbg.level);
        this.health = 5;
        this.setItem(bbg.getItem().copy());
        this.copyPosition(bbg);
        this.age = bbg.age;
        this.bobOffs = bbg.bobOffs;
    }
    
    @Override
    protected boolean isMovementNoisy() {
        return false;
    }
    
    @Override
    protected void defineSynchedData() {
        this.getEntityData().<ItemStack>define(ItemEntity.DATA_ITEM, ItemStack.EMPTY);
    }
    
    @Override
    public void tick() {
        if (this.getItem().isEmpty()) {
            this.remove();
            return;
        }
        super.tick();
        if (this.pickupDelay > 0 && this.pickupDelay != 32767) {
            --this.pickupDelay;
        }
        this.xo = this.getX();
        this.yo = this.getY();
        this.zo = this.getZ();
        final Vec3 dem2 = this.getDeltaMovement();
        if (this.isEyeInFluid(FluidTags.WATER)) {
            this.setUnderwaterMovement();
        }
        else if (this.isEyeInFluid(FluidTags.LAVA)) {
            this.setUnderLavaMovement();
        }
        else if (!this.isNoGravity()) {
            this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.04, 0.0));
        }
        if (this.level.isClientSide) {
            this.noPhysics = false;
        }
        else {
            this.noPhysics = !this.level.noCollision(this);
            if (this.noPhysics) {
                this.checkInBlock(this.getX(), (this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0, this.getZ());
            }
        }
        if (!this.onGround || Entity.getHorizontalDistanceSqr(this.getDeltaMovement()) > 9.999999747378752E-6 || (this.tickCount + this.getId()) % 4 == 0) {
            this.move(MoverType.SELF, this.getDeltaMovement());
            float float3 = 0.98f;
            if (this.onGround) {
                float3 = this.level.getBlockState(new BlockPos(this.getX(), this.getY() - 1.0, this.getZ())).getBlock().getFriction() * 0.98f;
            }
            this.setDeltaMovement(this.getDeltaMovement().multiply(float3, 0.98, float3));
            if (this.onGround) {
                this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, -0.5, 1.0));
            }
        }
        final boolean boolean3 = Mth.floor(this.xo) != Mth.floor(this.getX()) || Mth.floor(this.yo) != Mth.floor(this.getY()) || Mth.floor(this.zo) != Mth.floor(this.getZ());
        final int integer4 = boolean3 ? 2 : 40;
        if (this.tickCount % integer4 == 0) {
            if (this.level.getFluidState(this.blockPosition()).is(FluidTags.LAVA) && !this.fireImmune()) {
                this.playSound(SoundEvents.GENERIC_BURN, 0.4f, 2.0f + this.random.nextFloat() * 0.4f);
            }
            if (!this.level.isClientSide && this.isMergable()) {
                this.mergeWithNeighbours();
            }
        }
        if (this.age != -32768) {
            ++this.age;
        }
        this.hasImpulse |= this.updateInWaterStateAndDoFluidPushing();
        if (!this.level.isClientSide) {
            final double double5 = this.getDeltaMovement().subtract(dem2).lengthSqr();
            if (double5 > 0.01) {
                this.hasImpulse = true;
            }
        }
        if (!this.level.isClientSide && this.age >= 6000) {
            this.remove();
        }
    }
    
    private void setUnderwaterMovement() {
        final Vec3 dem2 = this.getDeltaMovement();
        this.setDeltaMovement(dem2.x * 0.9900000095367432, dem2.y + ((dem2.y < 0.05999999865889549) ? 5.0E-4f : 0.0f), dem2.z * 0.9900000095367432);
    }
    
    private void setUnderLavaMovement() {
        final Vec3 dem2 = this.getDeltaMovement();
        this.setDeltaMovement(dem2.x * 0.949999988079071, dem2.y + ((dem2.y < 0.05999999865889549) ? 5.0E-4f : 0.0f), dem2.z * 0.949999988079071);
    }
    
    private void mergeWithNeighbours() {
        if (!this.isMergable()) {
            return;
        }
        final List<ItemEntity> list2 = this.level.<ItemEntity>getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.5, 0.0, 0.5), bbg -> bbg != this && bbg.isMergable());
        for (final ItemEntity bbg2 : list2) {
            if (bbg2.isMergable()) {
                this.tryToMerge(bbg2);
                if (this.removed) {
                    break;
                }
                continue;
            }
        }
    }
    
    private boolean isMergable() {
        final ItemStack bki2 = this.getItem();
        return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < 6000 && bki2.getCount() < bki2.getMaxStackSize();
    }
    
    private void tryToMerge(final ItemEntity bbg) {
        final ItemStack bki3 = this.getItem();
        final ItemStack bki4 = bbg.getItem();
        if (!Objects.equals(this.getOwner(), bbg.getOwner()) || !areMergable(bki3, bki4)) {
            return;
        }
        if (bki4.getCount() < bki3.getCount()) {
            merge(this, bki3, bbg, bki4);
        }
        else {
            merge(bbg, bki4, this, bki3);
        }
    }
    
    public static boolean areMergable(final ItemStack bki1, final ItemStack bki2) {
        return bki2.getItem() == bki1.getItem() && bki2.getCount() + bki1.getCount() <= bki2.getMaxStackSize() && !(bki2.hasTag() ^ bki1.hasTag()) && (!bki2.hasTag() || bki2.getTag().equals(bki1.getTag()));
    }
    
    public static ItemStack merge(final ItemStack bki1, final ItemStack bki2, final int integer) {
        final int integer2 = Math.min(Math.min(bki1.getMaxStackSize(), integer) - bki1.getCount(), bki2.getCount());
        final ItemStack bki3 = bki1.copy();
        bki3.grow(integer2);
        bki2.shrink(integer2);
        return bki3;
    }
    
    private static void merge(final ItemEntity bbg, final ItemStack bki2, final ItemStack bki3) {
        final ItemStack bki4 = merge(bki2, bki3, 64);
        bbg.setItem(bki4);
    }
    
    private static void merge(final ItemEntity bbg1, final ItemStack bki2, final ItemEntity bbg3, final ItemStack bki4) {
        merge(bbg1, bki2, bki4);
        bbg1.pickupDelay = Math.max(bbg1.pickupDelay, bbg3.pickupDelay);
        bbg1.age = Math.min(bbg1.age, bbg3.age);
        if (bki4.isEmpty()) {
            bbg3.remove();
        }
    }
    
    @Override
    public boolean fireImmune() {
        return this.getItem().getItem().isFireResistant() || super.fireImmune();
    }
    
    @Override
    public boolean hurt(final DamageSource anw, final float float2) {
        if (this.isInvulnerableTo(anw)) {
            return false;
        }
        if (!this.getItem().isEmpty() && this.getItem().getItem() == Items.NETHER_STAR && anw.isExplosion()) {
            return false;
        }
        if (!this.getItem().getItem().canBeHurtBy(anw)) {
            return false;
        }
        this.markHurt();
        this.health -= (int)float2;
        if (this.health <= 0) {
            this.remove();
        }
        return false;
    }
    
    public void addAdditionalSaveData(final CompoundTag le) {
        le.putShort("Health", (short)this.health);
        le.putShort("Age", (short)this.age);
        le.putShort("PickupDelay", (short)this.pickupDelay);
        if (this.getThrower() != null) {
            le.putUUID("Thrower", this.getThrower());
        }
        if (this.getOwner() != null) {
            le.putUUID("Owner", this.getOwner());
        }
        if (!this.getItem().isEmpty()) {
            le.put("Item", this.getItem().save(new CompoundTag()));
        }
    }
    
    public void readAdditionalSaveData(final CompoundTag le) {
        this.health = le.getShort("Health");
        this.age = le.getShort("Age");
        if (le.contains("PickupDelay")) {
            this.pickupDelay = le.getShort("PickupDelay");
        }
        if (le.hasUUID("Owner")) {
            this.owner = le.getUUID("Owner");
        }
        if (le.hasUUID("Thrower")) {
            this.thrower = le.getUUID("Thrower");
        }
        final CompoundTag le2 = le.getCompound("Item");
        this.setItem(ItemStack.of(le2));
        if (this.getItem().isEmpty()) {
            this.remove();
        }
    }
    
    @Override
    public void playerTouch(final Player bec) {
        if (this.level.isClientSide) {
            return;
        }
        final ItemStack bki3 = this.getItem();
        final Item bke4 = bki3.getItem();
        final int integer5 = bki3.getCount();
        if (this.pickupDelay == 0 && (this.owner == null || this.owner.equals(bec.getUUID())) && bec.inventory.add(bki3)) {
            bec.take(this, integer5);
            if (bki3.isEmpty()) {
                this.remove();
                bki3.setCount(integer5);
            }
            bec.awardStat(Stats.ITEM_PICKED_UP.get(bke4), integer5);
            bec.onItemPickup(this);
        }
    }
    
    @Override
    public Component getName() {
        final Component mr2 = this.getCustomName();
        if (mr2 != null) {
            return mr2;
        }
        return new TranslatableComponent(this.getItem().getDescriptionId());
    }
    
    @Override
    public boolean isAttackable() {
        return false;
    }
    
    @Nullable
    @Override
    public Entity changeDimension(final ServerLevel zd) {
        final Entity aom3 = super.changeDimension(zd);
        if (!this.level.isClientSide && aom3 instanceof ItemEntity) {
            ((ItemEntity)aom3).mergeWithNeighbours();
        }
        return aom3;
    }
    
    public ItemStack getItem() {
        return this.getEntityData().<ItemStack>get(ItemEntity.DATA_ITEM);
    }
    
    public void setItem(final ItemStack bki) {
        this.getEntityData().<ItemStack>set(ItemEntity.DATA_ITEM, bki);
    }
    
    @Override
    public void onSyncedDataUpdated(final EntityDataAccessor<?> tq) {
        super.onSyncedDataUpdated(tq);
        if (ItemEntity.DATA_ITEM.equals(tq)) {
            this.getItem().setEntityRepresentation(this);
        }
    }
    
    @Nullable
    public UUID getOwner() {
        return this.owner;
    }
    
    public void setOwner(@Nullable final UUID uUID) {
        this.owner = uUID;
    }
    
    @Nullable
    public UUID getThrower() {
        return this.thrower;
    }
    
    public void setThrower(@Nullable final UUID uUID) {
        this.thrower = uUID;
    }
    
    public int getAge() {
        return this.age;
    }
    
    public void setDefaultPickUpDelay() {
        this.pickupDelay = 10;
    }
    
    public void setNoPickUpDelay() {
        this.pickupDelay = 0;
    }
    
    public void setNeverPickUp() {
        this.pickupDelay = 32767;
    }
    
    public void setPickUpDelay(final int integer) {
        this.pickupDelay = integer;
    }
    
    public boolean hasPickUpDelay() {
        return this.pickupDelay > 0;
    }
    
    public void setExtendedLifetime() {
        this.age = -6000;
    }
    
    public void makeFakeItem() {
        this.setNeverPickUp();
        this.age = 5999;
    }
    
    public float getSpin(final float float1) {
        return (this.getAge() + float1) / 20.0f + this.bobOffs;
    }
    
    @Override
    public Packet<?> getAddEntityPacket() {
        return new ClientboundAddEntityPacket(this);
    }
    
    public ItemEntity copy() {
        return new ItemEntity(this);
    }
    
    static {
        DATA_ITEM = SynchedEntityData.<ItemStack>defineId(ItemEntity.class, EntityDataSerializers.ITEM_STACK);
    }
}
