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

import java.util.AbstractList;
import net.minecraft.world.level.block.state.StateHolder;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.world.level.block.Block;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.Tag;
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.LivingEntity;
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 fu3 : BlockPos.betweenClosed(this.worldPosition.offset(-1, -1, -1), this.worldPosition.offset(1, 1, 1))) {
            if (this.level.getBlockState(fu3).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 bec, final BlockState cfj, final BeeReleaseStatus b) {
        final List<Entity> list5 = this.releaseAllOccupants(cfj, b);
        if (bec != null) {
            for (final Entity aom7 : list5) {
                if (aom7 instanceof Bee) {
                    final Bee ayl8 = (Bee)aom7;
                    if (bec.position().distanceToSqr(aom7.position()) > 16.0) {
                        continue;
                    }
                    if (!this.isSedated()) {
                        ayl8.setTarget(bec);
                    }
                    else {
                        ayl8.setStayOutOfHiveCountdown(400);
                    }
                }
            }
        }
    }
    
    private List<Entity> releaseAllOccupants(final BlockState cfj, final BeeReleaseStatus b) {
        final List<Entity> list4 = Lists.newArrayList();
        this.stored.removeIf(a -> this.releaseOccupant(cfj, a, list4, b));
        return list4;
    }
    
    public void addOccupant(final Entity aom, final boolean boolean2) {
        this.addOccupantWithPresetTicks(aom, boolean2, 0);
    }
    
    public int getOccupantCount() {
        return this.stored.size();
    }
    
    public static int getHoneyLevel(final BlockState cfj) {
        return cfj.<Integer>getValue((Property<Integer>)BeehiveBlock.HONEY_LEVEL);
    }
    
    public boolean isSedated() {
        return CampfireBlock.isSmokeyPos(this.level, this.getBlockPos());
    }
    
    protected void sendDebugPackets() {
        DebugPackets.sendHiveInfo(this);
    }
    
    public void addOccupantWithPresetTicks(final Entity aom, final boolean boolean2, final int integer) {
        if (this.stored.size() >= 3) {
            return;
        }
        aom.stopRiding();
        aom.ejectPassengers();
        final CompoundTag le5 = new CompoundTag();
        aom.save(le5);
        this.stored.add(new BeeData(le5, integer, boolean2 ? 2400 : 600));
        if (this.level != null) {
            if (aom instanceof Bee) {
                final Bee ayl6 = (Bee)aom;
                if (ayl6.hasSavedFlowerPos() && (!this.hasSavedFlowerPos() || this.level.random.nextBoolean())) {
                    this.savedFlowerPos = ayl6.getSavedFlowerPos();
                }
            }
            final BlockPos fu6 = this.getBlockPos();
            this.level.playSound(null, fu6.getX(), fu6.getY(), fu6.getZ(), SoundEvents.BEEHIVE_ENTER, SoundSource.BLOCKS, 1.0f, 1.0f);
        }
        aom.remove();
    }
    
    private boolean releaseOccupant(final BlockState cfj, final BeeData a, @Nullable final List<Entity> list, final BeeReleaseStatus b) {
        if ((this.level.isNight() || this.level.isRaining()) && b != BeeReleaseStatus.EMERGENCY) {
            return false;
        }
        final BlockPos fu6 = this.getBlockPos();
        final CompoundTag le7 = a.entityData;
        le7.remove("Passengers");
        le7.remove("Leash");
        le7.remove("UUID");
        final Direction fz8 = cfj.<Direction>getValue((Property<Direction>)BeehiveBlock.FACING);
        final BlockPos fu7 = fu6.relative(fz8);
        final boolean boolean10 = !this.level.getBlockState(fu7).getCollisionShape(this.level, fu7).isEmpty();
        if (boolean10 && b != BeeReleaseStatus.EMERGENCY) {
            return false;
        }
        final Entity aom2 = EntityType.loadEntityRecursive(le7, this.level, aom -> aom);
        if (aom2 == null) {
            return false;
        }
        if (!aom2.getType().is(EntityTypeTags.BEEHIVE_INHABITORS)) {
            return false;
        }
        if (aom2 instanceof Bee) {
            final Bee ayl12 = (Bee)aom2;
            if (this.hasSavedFlowerPos() && !ayl12.hasSavedFlowerPos() && this.level.random.nextFloat() < 0.9f) {
                ayl12.setSavedFlowerPos(this.savedFlowerPos);
            }
            if (b == BeeReleaseStatus.HONEY_DELIVERED) {
                ayl12.dropOffNectar();
                if (cfj.getBlock().is(BlockTags.BEEHIVES)) {
                    final int integer13 = getHoneyLevel(cfj);
                    if (integer13 < 5) {
                        int integer14 = (this.level.random.nextInt(100) == 0) ? 2 : 1;
                        if (integer13 + integer14 > 5) {
                            --integer14;
                        }
                        this.level.setBlockAndUpdate(this.getBlockPos(), ((StateHolder<O, BlockState>)cfj).<Comparable, Integer>setValue((Property<Comparable>)BeehiveBlock.HONEY_LEVEL, integer13 + integer14));
                    }
                }
            }
            this.setBeeReleaseData(a.ticksInHive, ayl12);
            if (list != null) {
                list.add(ayl12);
            }
            final float float13 = aom2.getBbWidth();
            final double double14 = boolean10 ? 0.0 : (0.55 + float13 / 2.0f);
            final double double15 = fu6.getX() + 0.5 + double14 * fz8.getStepX();
            final double double16 = fu6.getY() + 0.5 - aom2.getBbHeight() / 2.0f;
            final double double17 = fu6.getZ() + 0.5 + double14 * fz8.getStepZ();
            aom2.moveTo(double15, double16, double17, aom2.yRot, aom2.xRot);
        }
        this.level.playSound(null, fu6, SoundEvents.BEEHIVE_EXIT, SoundSource.BLOCKS, 1.0f, 1.0f);
        return this.level.addFreshEntity(aom2);
    }
    
    private void setBeeReleaseData(final int integer, final Bee ayl) {
        final int integer2 = ayl.getAge();
        if (integer2 < 0) {
            ayl.setAge(Math.min(0, integer2 + integer));
        }
        else if (integer2 > 0) {
            ayl.setAge(Math.max(0, integer2 - integer));
        }
        ayl.setInLoveTime(Math.max(0, ayl.getInLoveTime() - integer));
        ayl.resetTicksWithoutNectarSinceExitingHive();
    }
    
    private boolean hasSavedFlowerPos() {
        return this.savedFlowerPos != null;
    }
    
    private void tickOccupants() {
        final Iterator<BeeData> iterator2 = this.stored.iterator();
        final BlockState cfj3 = this.getBlockState();
        while (iterator2.hasNext()) {
            final BeeData a4 = iterator2.next();
            if (a4.ticksInHive > a4.minOccupationTicks) {
                final BeeReleaseStatus b5 = a4.entityData.getBoolean("HasNectar") ? BeeReleaseStatus.HONEY_DELIVERED : BeeReleaseStatus.BEE_RELEASED;
                if (this.releaseOccupant(cfj3, a4, null, b5)) {
                    iterator2.remove();
                }
            }
            a4.ticksInHive++;
        }
    }
    
    @Override
    public void tick() {
        if (this.level.isClientSide) {
            return;
        }
        this.tickOccupants();
        final BlockPos fu2 = this.getBlockPos();
        if (this.stored.size() > 0 && this.level.getRandom().nextDouble() < 0.005) {
            final double double3 = fu2.getX() + 0.5;
            final double double4 = fu2.getY();
            final double double5 = fu2.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 BlockState cfj, final CompoundTag le) {
        super.load(cfj, le);
        this.stored.clear();
        final ListTag lk4 = le.getList("Bees", 10);
        for (int integer5 = 0; integer5 < lk4.size(); ++integer5) {
            final CompoundTag le2 = lk4.getCompound(integer5);
            final BeeData a7 = new BeeData(le2.getCompound("EntityData"), le2.getInt("TicksInHive"), le2.getInt("MinOccupationTicks"));
            this.stored.add(a7);
        }
        this.savedFlowerPos = null;
        if (le.contains("FlowerPos")) {
            this.savedFlowerPos = NbtUtils.readBlockPos(le.getCompound("FlowerPos"));
        }
    }
    
    @Override
    public CompoundTag save(final CompoundTag le) {
        super.save(le);
        le.put("Bees", this.writeBees());
        if (this.hasSavedFlowerPos()) {
            le.put("FlowerPos", NbtUtils.writeBlockPos(this.savedFlowerPos));
        }
        return le;
    }
    
    public ListTag writeBees() {
        final ListTag lk2 = new ListTag();
        for (final BeeData a4 : this.stored) {
            a4.entityData.remove("UUID");
            final CompoundTag le5 = new CompoundTag();
            le5.put("EntityData", a4.entityData);
            le5.putInt("TicksInHive", a4.ticksInHive);
            le5.putInt("MinOccupationTicks", a4.minOccupationTicks);
            ((AbstractList<CompoundTag>)lk2).add(le5);
        }
        return lk2;
    }
    
    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 le, final int integer2, final int integer3) {
            le.remove("UUID");
            this.entityData = le;
            this.ticksInHive = integer2;
            this.minOccupationTicks = integer3;
        }
    }
}
