package net.minecraft.world.level.block;

import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.function.BiPredicate;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import java.util.function.Function;
import net.minecraft.world.level.block.entity.BlockEntityType;

public class DoubleBlockCombiner {
    public static <S extends BlockEntity> NeighborCombineResult<S> combineWithNeigbour(final BlockEntityType<S> bwm, final Function<BlockState, BlockType> function2, final Function<BlockState, Direction> function3, final DirectionProperty bze, final BlockState byj, final LevelAccessor bjx, final BlockPos fk, final BiPredicate<LevelAccessor, BlockPos> biPredicate) {
        final S bwl9 = bwm.getBlockEntity(bjx, fk);
        if (bwl9 == null) {
            return Combiner::acceptNone;
        }
        if (biPredicate.test(bjx, fk)) {
            return Combiner::acceptNone;
        }
        final BlockType a10 = function2.apply(byj);
        final boolean boolean11 = a10 == BlockType.SINGLE;
        final boolean boolean12 = a10 == BlockType.FIRST;
        if (boolean11) {
            return new NeighborCombineResult.Single<S>(bwl9);
        }
        final BlockPos fk2 = fk.relative(function3.apply(byj));
        final BlockState byj2 = bjx.getBlockState(fk2);
        if (byj2.getBlock() == byj.getBlock()) {
            final BlockType a11 = function2.apply(byj2);
            if (a11 != BlockType.SINGLE && a10 != a11 && byj2.<Comparable>getValue((Property<Comparable>)bze) == byj.<Comparable>getValue((Property<Comparable>)bze)) {
                if (biPredicate.test(bjx, fk2)) {
                    return Combiner::acceptNone;
                }
                final S bwl10 = bwm.getBlockEntity(bjx, fk2);
                if (bwl10 != null) {
                    final S bwl11 = boolean12 ? bwl9 : bwl10;
                    final S bwl12 = boolean12 ? bwl10 : bwl9;
                    return new NeighborCombineResult.Double<S>(bwl11, bwl12);
                }
            }
        }
        return new NeighborCombineResult.Single<S>(bwl9);
    }
    
    public enum BlockType {
        SINGLE, 
        FIRST, 
        SECOND;
    }
    
    public interface NeighborCombineResult<S> {
         <T> T apply(final Combiner<? super S, T> b);
        
        public static final class Double<S> implements NeighborCombineResult<S> {
            private final S first;
            private final S second;
            
            public Double(final S object1, final S object2) {
                this.first = object1;
                this.second = object2;
            }
            
            @Override
            public <T> T apply(final Combiner<? super S, T> b) {
                return b.acceptDouble(this.first, this.second);
            }
        }
        
        public static final class Single<S> implements NeighborCombineResult<S> {
            private final S single;
            
            public Single(final S object) {
                this.single = object;
            }
            
            @Override
            public <T> T apply(final Combiner<? super S, T> b) {
                return b.acceptSingle(this.single);
            }
        }
    }
    
    public interface Combiner<S, T> {
        T acceptDouble(final S object1, final S object2);
        
        T acceptSingle(final S object);
        
        T acceptNone();
    }
}
