package net.minecraft.world.level;

import net.minecraft.world.level.material.Fluid;
import net.minecraft.tags.Tag;
import net.minecraft.tags.FluidTags;
import net.minecraft.core.Direction;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.state.BlockState;
import java.util.stream.Stream;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.levelgen.Heightmap;
import javax.annotation.Nullable;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.biome.BiomeManager;

public interface LevelReader extends BlockAndTintGetter, CollisionGetter, BiomeManager.NoiseBiomeSource {
    @Nullable
    ChunkAccess getChunk(final int integer1, final int integer2, final ChunkStatus chc, final boolean boolean4);
    
    @Deprecated
    boolean hasChunk(final int integer1, final int integer2);
    
    int getHeight(final Heightmap.Types a, final int integer2, final int integer3);
    
    int getSkyDarken();
    
    BiomeManager getBiomeManager();
    
    default Biome getBiome(final BlockPos fu) {
        return this.getBiomeManager().getBiome(fu);
    }
    
    default Stream<BlockState> getBlockStatesIfLoaded(final AABB deg) {
        final int integer3 = Mth.floor(deg.minX);
        final int integer4 = Mth.floor(deg.maxX);
        final int integer5 = Mth.floor(deg.minY);
        final int integer6 = Mth.floor(deg.maxY);
        final int integer7 = Mth.floor(deg.minZ);
        final int integer8 = Mth.floor(deg.maxZ);
        if (this.hasChunksAt(integer3, integer5, integer7, integer4, integer6, integer8)) {
            return this.getBlockStates(deg);
        }
        return Stream.<BlockState>empty();
    }
    
    default int getBlockTint(final BlockPos fu, final ColorResolver colorResolver) {
        return colorResolver.getColor(this.getBiome(fu), fu.getX(), fu.getZ());
    }
    
    default Biome getNoiseBiome(final int integer1, final int integer2, final int integer3) {
        final ChunkAccess cgy5 = this.getChunk(integer1 >> 2, integer3 >> 2, ChunkStatus.BIOMES, false);
        if (cgy5 != null && cgy5.getBiomes() != null) {
            return cgy5.getBiomes().getNoiseBiome(integer1, integer2, integer3);
        }
        return this.getUncachedNoiseBiome(integer1, integer2, integer3);
    }
    
    Biome getUncachedNoiseBiome(final int integer1, final int integer2, final int integer3);
    
    boolean isClientSide();
    
    @Deprecated
    int getSeaLevel();
    
    DimensionType dimensionType();
    
    default BlockPos getHeightmapPos(final Heightmap.Types a, final BlockPos fu) {
        return new BlockPos(fu.getX(), this.getHeight(a, fu.getX(), fu.getZ()), fu.getZ());
    }
    
    default boolean isEmptyBlock(final BlockPos fu) {
        return this.getBlockState(fu).isAir();
    }
    
    default boolean canSeeSkyFromBelowWater(final BlockPos fu) {
        if (fu.getY() >= this.getSeaLevel()) {
            return this.canSeeSky(fu);
        }
        BlockPos fu2 = new BlockPos(fu.getX(), this.getSeaLevel(), fu.getZ());
        if (!this.canSeeSky(fu2)) {
            return false;
        }
        for (fu2 = fu2.below(); fu2.getY() > fu.getY(); fu2 = fu2.below()) {
            final BlockState cfj4 = this.getBlockState(fu2);
            if (cfj4.getLightBlock(this, fu2) > 0 && !cfj4.getMaterial().isLiquid()) {
                return false;
            }
        }
        return true;
    }
    
    @Deprecated
    default float getBrightness(final BlockPos fu) {
        return this.dimensionType().brightness(this.getMaxLocalRawBrightness(fu));
    }
    
    default int getDirectSignal(final BlockPos fu, final Direction fz) {
        return this.getBlockState(fu).getDirectSignal(this, fu, fz);
    }
    
    default ChunkAccess getChunk(final BlockPos fu) {
        return this.getChunk(fu.getX() >> 4, fu.getZ() >> 4);
    }
    
    default ChunkAccess getChunk(final int integer1, final int integer2) {
        return this.getChunk(integer1, integer2, ChunkStatus.FULL, true);
    }
    
    default ChunkAccess getChunk(final int integer1, final int integer2, final ChunkStatus chc) {
        return this.getChunk(integer1, integer2, chc, true);
    }
    
    @Nullable
    default BlockGetter getChunkForCollisions(final int integer1, final int integer2) {
        return this.getChunk(integer1, integer2, ChunkStatus.EMPTY, false);
    }
    
    default boolean isWaterAt(final BlockPos fu) {
        return this.getFluidState(fu).is(FluidTags.WATER);
    }
    
    default boolean containsAnyLiquid(final AABB deg) {
        final int integer3 = Mth.floor(deg.minX);
        final int integer4 = Mth.ceil(deg.maxX);
        final int integer5 = Mth.floor(deg.minY);
        final int integer6 = Mth.ceil(deg.maxY);
        final int integer7 = Mth.floor(deg.minZ);
        final int integer8 = Mth.ceil(deg.maxZ);
        final BlockPos.MutableBlockPos a9 = new BlockPos.MutableBlockPos();
        for (int integer9 = integer3; integer9 < integer4; ++integer9) {
            for (int integer10 = integer5; integer10 < integer6; ++integer10) {
                for (int integer11 = integer7; integer11 < integer8; ++integer11) {
                    final BlockState cfj13 = this.getBlockState(a9.set(integer9, integer10, integer11));
                    if (!cfj13.getFluidState().isEmpty()) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    
    default int getMaxLocalRawBrightness(final BlockPos fu) {
        return this.getMaxLocalRawBrightness(fu, this.getSkyDarken());
    }
    
    default int getMaxLocalRawBrightness(final BlockPos fu, final int integer) {
        if (fu.getX() < -30000000 || fu.getZ() < -30000000 || fu.getX() >= 30000000 || fu.getZ() >= 30000000) {
            return 15;
        }
        return this.getRawBrightness(fu, integer);
    }
    
    @Deprecated
    default boolean hasChunkAt(final BlockPos fu) {
        return this.hasChunk(fu.getX() >> 4, fu.getZ() >> 4);
    }
    
    @Deprecated
    default boolean hasChunksAt(final BlockPos fu1, final BlockPos fu2) {
        return this.hasChunksAt(fu1.getX(), fu1.getY(), fu1.getZ(), fu2.getX(), fu2.getY(), fu2.getZ());
    }
    
    @Deprecated
    default boolean hasChunksAt(int integer1, final int integer2, int integer3, int integer4, final int integer5, int integer6) {
        if (integer5 < 0 || integer2 >= 256) {
            return false;
        }
        integer1 >>= 4;
        integer3 >>= 4;
        integer4 >>= 4;
        integer6 >>= 4;
        for (int integer7 = integer1; integer7 <= integer4; ++integer7) {
            for (int integer8 = integer3; integer8 <= integer6; ++integer8) {
                if (!this.hasChunk(integer7, integer8)) {
                    return false;
                }
            }
        }
        return true;
    }
}
