package net.minecraft.world.level.block.entity;

import java.util.AbstractList;
import net.minecraft.world.level.block.state.AbstractStateHolder;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.EntityTypeTags;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundSource;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.world.level.block.CampfireBlock;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.BeehiveBlock;
import net.minecraft.world.entity.animal.Bee;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.state.BlockState;
import java.util.Iterator;
import net.minecraft.world.level.block.FireBlock;
import net.minecraft.world.entity.player.Player;
import com.google.common.collect.Lists;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import java.util.List;

public class BeehiveBlockEntity extends BlockEntity implements TickableBlockEntity {
    private final List<BeeData> stored;
    @Nullable
    private BlockPos savedFlowerPos;
    
    public BeehiveBlockEntity() {
        super(BlockEntityType.BEEHIVE);
        this.stored = Lists.newArrayList();
        this.savedFlowerPos = null;
    }
    
    @Override
    public void setChanged() {
        if (this.isFireNearby()) {
            this.emptyAllLivingFromHive(null, this.level.getBlockState(this.getBlockPos()), BeeReleaseStatus.EMERGENCY);
        }
        super.setChanged();
    }
    
    public boolean isFireNearby() {
        if (this.level == null) {
            return false;
        }
        for (final BlockPos fk3 : BlockPos.betweenClosed(this.worldPosition.offset(-1, -1, -1), this.worldPosition.offset(1, 1, 1))) {
            if (this.level.getBlockState(fk3).getBlock() instanceof FireBlock) {
                return true;
            }
        }
        return false;
    }
    
    public boolean isEmpty() {
        return this.stored.isEmpty();
    }
    
    public boolean isFull() {
        return this.stored.size() == 3;
    }
    
    public void emptyAllLivingFromHive(@Nullable final Player ayj, final BlockState byj, final BeeReleaseStatus b) {
        final List<Entity> list5 = this.releaseAllOccupants(byj, b);
        if (ayj != null) {
            for (final Entity akq7 : list5) {
                if (akq7 instanceof Bee) {
                    final Bee atd8 = (Bee)akq7;
                    if (ayj.position().distanceToSqr(akq7.position()) > 16.0) {
                        continue;
                    }
                    if (!this.isSedated()) {
                        atd8.makeAngry(ayj);
                    }
                    else {
                        atd8.setStayOutOfHiveCountdown(400);
                    }
                }
            }
        }
    }
    
    private List<Entity> releaseAllOccupants(final BlockState byj, final BeeReleaseStatus b) {
        final List<Entity> list4 = Lists.newArrayList();
        this.stored.removeIf(a -> this.releaseOccupant(byj, a.entityData, list4, b));
        return list4;
    }
    
    public void addOccupant(final Entity akq, final boolean boolean2) {
        this.addOccupantWithPresetTicks(akq, boolean2, 0);
    }
    
    public int getOccupantCount() {
        return this.stored.size();
    }
    
    public static int getHoneyLevel(final BlockState byj) {
        return byj.<Integer>getValue((Property<Integer>)BeehiveBlock.HONEY_LEVEL);
    }
    
    public boolean isSedated() {
        return CampfireBlock.isSmokeyPos(this.level, this.getBlockPos(), 5);
    }
    
    protected void sendDebugPackets() {
        DebugPackets.sendHiveInfo(this);
    }
    
    public void addOccupantWithPresetTicks(final Entity akq, final boolean boolean2, final int integer) {
        if (this.stored.size() >= 3) {
            return;
        }
        akq.stopRiding();
        akq.ejectPassengers();
        final CompoundTag jt5 = new CompoundTag();
        akq.save(jt5);
        this.stored.add(new BeeData(jt5, integer, boolean2 ? 2400 : 600));
        if (this.level != null) {
            if (akq instanceof Bee) {
                final Bee atd6 = (Bee)akq;
                if (atd6.hasSavedFlowerPos() && (!this.hasSavedFlowerPos() || this.level.random.nextBoolean())) {
                    this.savedFlowerPos = atd6.getSavedFlowerPos();
                }
            }
            final BlockPos fk6 = this.getBlockPos();
            this.level.playSound(null, fk6.getX(), fk6.getY(), fk6.getZ(), SoundEvents.BEEHIVE_ENTER, SoundSource.BLOCKS, 1.0f, 1.0f);
        }
        akq.remove();
    }
    
    private boolean releaseOccupant(final BlockState byj, final CompoundTag jt, @Nullable final List<Entity> list, final BeeReleaseStatus b) {
        final BlockPos fk6 = this.getBlockPos();
        if ((this.level.isNight() || this.level.isRaining()) && b != BeeReleaseStatus.EMERGENCY) {
            return false;
        }
        jt.remove("Passengers");
        jt.remove("Leash");
        jt.removeUUID("UUID");
        final Direction fp7 = byj.<Direction>getValue((Property<Direction>)BeehiveBlock.FACING);
        final BlockPos fk7 = fk6.relative(fp7);
        final boolean boolean9 = !this.level.getBlockState(fk7).getCollisionShape(this.level, fk7).isEmpty();
        if (boolean9 && b != BeeReleaseStatus.EMERGENCY) {
            return false;
        }
        final Entity akq2 = EntityType.loadEntityRecursive(jt, this.level, akq -> akq);
        if (akq2 == null) {
            return false;
        }
        final float float11 = akq2.getBbWidth();
        final double double12 = boolean9 ? 0.0 : (0.55 + float11 / 2.0f);
        final double double13 = fk6.getX() + 0.5 + double12 * fp7.getStepX();
        final double double14 = fk6.getY() + 0.5 - akq2.getBbHeight() / 2.0f;
        final double double15 = fk6.getZ() + 0.5 + double12 * fp7.getStepZ();
        akq2.moveTo(double13, double14, double15, akq2.yRot, akq2.xRot);
        if (!akq2.getType().is(EntityTypeTags.BEEHIVE_INHABITORS)) {
            return false;
        }
        if (akq2 instanceof Bee) {
            final Bee atd20 = (Bee)akq2;
            if (this.hasSavedFlowerPos() && !atd20.hasSavedFlowerPos() && this.level.random.nextFloat() < 0.9f) {
                atd20.setSavedFlowerPos(this.savedFlowerPos);
            }
            if (b == BeeReleaseStatus.HONEY_DELIVERED) {
                atd20.dropOffNectar();
                if (byj.getBlock().is(BlockTags.BEEHIVES)) {
                    final int integer21 = getHoneyLevel(byj);
                    if (integer21 < 5) {
                        int integer22 = (this.level.random.nextInt(100) == 0) ? 2 : 1;
                        if (integer21 + integer22 > 5) {
                            --integer22;
                        }
                        this.level.setBlockAndUpdate(this.getBlockPos(), ((AbstractStateHolder<O, BlockState>)byj).<Comparable, Integer>setValue((Property<Comparable>)BeehiveBlock.HONEY_LEVEL, integer21 + integer22));
                    }
                }
            }
            atd20.resetTicksWithoutNectarSinceExitingHive();
            if (list != null) {
                list.add(atd20);
            }
        }
        final BlockPos fk8 = this.getBlockPos();
        this.level.playSound(null, fk8.getX(), fk8.getY(), fk8.getZ(), SoundEvents.BEEHIVE_EXIT, SoundSource.BLOCKS, 1.0f, 1.0f);
        return this.level.addFreshEntity(akq2);
    }
    
    private boolean hasSavedFlowerPos() {
        return this.savedFlowerPos != null;
    }
    
    private void tickOccupants() {
        final Iterator<BeeData> iterator2 = this.stored.iterator();
        final BlockState byj3 = this.getBlockState();
        while (iterator2.hasNext()) {
            final BeeData a4 = iterator2.next();
            if (a4.ticksInHive > a4.minOccupationTicks) {
                final CompoundTag jt5 = a4.entityData;
                final BeeReleaseStatus b6 = jt5.getBoolean("HasNectar") ? BeeReleaseStatus.HONEY_DELIVERED : BeeReleaseStatus.BEE_RELEASED;
                if (!this.releaseOccupant(byj3, jt5, null, b6)) {
                    continue;
                }
                iterator2.remove();
            }
            else {
                a4.ticksInHive++;
            }
        }
    }
    
    @Override
    public void tick() {
        if (this.level.isClientSide) {
            return;
        }
        this.tickOccupants();
        final BlockPos fk2 = this.getBlockPos();
        if (this.stored.size() > 0 && this.level.getRandom().nextDouble() < 0.005) {
            final double double3 = fk2.getX() + 0.5;
            final double double4 = fk2.getY();
            final double double5 = fk2.getZ() + 0.5;
            this.level.playSound(null, double3, double4, double5, SoundEvents.BEEHIVE_WORK, SoundSource.BLOCKS, 1.0f, 1.0f);
        }
        this.sendDebugPackets();
    }
    
    @Override
    public void load(final CompoundTag jt) {
        super.load(jt);
        this.stored.clear();
        final ListTag jz3 = jt.getList("Bees", 10);
        for (int integer4 = 0; integer4 < jz3.size(); ++integer4) {
            final CompoundTag jt2 = jz3.getCompound(integer4);
            final BeeData a6 = new BeeData(jt2.getCompound("EntityData"), jt2.getInt("TicksInHive"), jt2.getInt("MinOccupationTicks"));
            this.stored.add(a6);
        }
        this.savedFlowerPos = null;
        if (jt.contains("FlowerPos")) {
            this.savedFlowerPos = NbtUtils.readBlockPos(jt.getCompound("FlowerPos"));
        }
    }
    
    @Override
    public CompoundTag save(final CompoundTag jt) {
        super.save(jt);
        jt.put("Bees", this.writeBees());
        if (this.hasSavedFlowerPos()) {
            jt.put("FlowerPos", NbtUtils.writeBlockPos(this.savedFlowerPos));
        }
        return jt;
    }
    
    public ListTag writeBees() {
        final ListTag jz2 = new ListTag();
        for (final BeeData a4 : this.stored) {
            a4.entityData.removeUUID("UUID");
            final CompoundTag jt5 = new CompoundTag();
            jt5.put("EntityData", a4.entityData);
            jt5.putInt("TicksInHive", a4.ticksInHive);
            jt5.putInt("MinOccupationTicks", a4.minOccupationTicks);
            ((AbstractList<CompoundTag>)jz2).add(jt5);
        }
        return jz2;
    }
    
    public enum BeeReleaseStatus {
        HONEY_DELIVERED, 
        BEE_RELEASED, 
        EMERGENCY;
    }
    
    static class BeeData {
        private final CompoundTag entityData;
        private int ticksInHive;
        private final int minOccupationTicks;
        
        private BeeData(final CompoundTag jt, final int integer2, final int integer3) {
            jt.removeUUID("UUID");
            this.entityData = jt;
            this.ticksInHive = integer2;
            this.minOccupationTicks = integer3;
        }
    }
}
