package net.minecraft.world.level;

import net.minecraft.util.Mth;
import java.util.function.Function;
import java.util.function.BiFunction;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.phys.Vec3;
import net.minecraft.core.Direction;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.block.state.BlockState;
import javax.annotation.Nullable;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.core.BlockPos;

public interface BlockGetter {
    @Nullable
    BlockEntity getBlockEntity(final BlockPos fk);
    
    BlockState getBlockState(final BlockPos fk);
    
    FluidState getFluidState(final BlockPos fk);
    
    default int getLightEmission(final BlockPos fk) {
        return this.getBlockState(fk).getLightEmission();
    }
    
    default int getMaxLightLevel() {
        return 15;
    }
    
    default int getMaxBuildHeight() {
        return 256;
    }
    
    default BlockHitResult clip(final ClipContext bjj) {
        final BlockState byj4;
        final FluidState coj5;
        final Vec3 cvl6;
        final Vec3 cvl7;
        final VoxelShape cwf8;
        final BlockHitResult cvg9;
        final VoxelShape cwf9;
        final BlockHitResult cvg10;
        final double double12;
        final double double13;
        final Vec3 cvl8;
        return BlockGetter.<BlockHitResult>traverseBlocks(bjj, (bjj, fk) -> {
            byj4 = this.getBlockState(fk);
            coj5 = this.getFluidState(fk);
            cvl6 = bjj.getFrom();
            cvl7 = bjj.getTo();
            cwf8 = bjj.getBlockShape(byj4, this, fk);
            cvg9 = this.clipWithInteractionOverride(cvl6, cvl7, fk, cwf8, byj4);
            cwf9 = bjj.getFluidShape(coj5, this, fk);
            cvg10 = cwf9.clip(cvl6, cvl7, fk);
            double12 = ((cvg9 == null) ? Double.MAX_VALUE : bjj.getFrom().distanceToSqr(cvg9.getLocation()));
            double13 = ((cvg10 == null) ? Double.MAX_VALUE : bjj.getFrom().distanceToSqr(cvg10.getLocation()));
            return (double12 <= double13) ? cvg9 : cvg10;
        }, bjj -> {
            cvl8 = bjj.getFrom().subtract(bjj.getTo());
            return BlockHitResult.miss(bjj.getTo(), Direction.getNearest(cvl8.x, cvl8.y, cvl8.z), new BlockPos(bjj.getTo()));
        });
    }
    
    @Nullable
    default BlockHitResult clipWithInteractionOverride(final Vec3 cvl1, final Vec3 cvl2, final BlockPos fk, final VoxelShape cwf, final BlockState byj) {
        final BlockHitResult cvg7 = cwf.clip(cvl1, cvl2, fk);
        if (cvg7 != null) {
            final BlockHitResult cvg8 = byj.getInteractionShape(this, fk).clip(cvl1, cvl2, fk);
            if (cvg8 != null && cvg8.getLocation().subtract(cvl1).lengthSqr() < cvg7.getLocation().subtract(cvl1).lengthSqr()) {
                return cvg7.withDirection(cvg8.getDirection());
            }
        }
        return cvg7;
    }
    
    default <T> T traverseBlocks(final ClipContext bjj, final BiFunction<ClipContext, BlockPos, T> biFunction, final Function<ClipContext, T> function) {
        final Vec3 cvl4 = bjj.getFrom();
        final Vec3 cvl5 = bjj.getTo();
        if (cvl4.equals(cvl5)) {
            return function.apply(bjj);
        }
        final double double6 = Mth.lerp(-1.0E-7, cvl5.x, cvl4.x);
        final double double7 = Mth.lerp(-1.0E-7, cvl5.y, cvl4.y);
        final double double8 = Mth.lerp(-1.0E-7, cvl5.z, cvl4.z);
        final double double9 = Mth.lerp(-1.0E-7, cvl4.x, cvl5.x);
        final double double10 = Mth.lerp(-1.0E-7, cvl4.y, cvl5.y);
        final double double11 = Mth.lerp(-1.0E-7, cvl4.z, cvl5.z);
        int integer18 = Mth.floor(double9);
        int integer19 = Mth.floor(double10);
        int integer20 = Mth.floor(double11);
        final BlockPos.MutableBlockPos a21 = new BlockPos.MutableBlockPos(integer18, integer19, integer20);
        final T object22 = biFunction.apply(bjj, a21);
        if (object22 != null) {
            return object22;
        }
        final double double12 = double6 - double9;
        final double double13 = double7 - double10;
        final double double14 = double8 - double11;
        final int integer21 = Mth.sign(double12);
        final int integer22 = Mth.sign(double13);
        final int integer23 = Mth.sign(double14);
        final double double15 = (integer21 == 0) ? Double.MAX_VALUE : (integer21 / double12);
        final double double16 = (integer22 == 0) ? Double.MAX_VALUE : (integer22 / double13);
        final double double17 = (integer23 == 0) ? Double.MAX_VALUE : (integer23 / double14);
        double double18 = double15 * ((integer21 > 0) ? (1.0 - Mth.frac(double9)) : Mth.frac(double9));
        double double19 = double16 * ((integer22 > 0) ? (1.0 - Mth.frac(double10)) : Mth.frac(double10));
        double double20 = double17 * ((integer23 > 0) ? (1.0 - Mth.frac(double11)) : Mth.frac(double11));
        while (double18 <= 1.0 || double19 <= 1.0 || double20 <= 1.0) {
            if (double18 < double19) {
                if (double18 < double20) {
                    integer18 += integer21;
                    double18 += double15;
                }
                else {
                    integer20 += integer23;
                    double20 += double17;
                }
            }
            else if (double19 < double20) {
                integer19 += integer22;
                double19 += double16;
            }
            else {
                integer20 += integer23;
                double20 += double17;
            }
            final T object23 = biFunction.apply(bjj, a21.set(integer18, integer19, integer20));
            if (object23 != null) {
                return object23;
            }
        }
        return function.apply(bjj);
    }
}
