package net.minecraft.world.level;

import java.util.function.Predicate;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.Vec3;

public class ClipContext {
    private final Vec3 from;
    private final Vec3 to;
    private final Block block;
    private final Fluid fluid;
    private final CollisionContext collisionContext;
    
    public ClipContext(final Vec3 dem1, final Vec3 dem2, final Block a, final Fluid b, final Entity aom) {
        this.from = dem1;
        this.to = dem2;
        this.block = a;
        this.fluid = b;
        this.collisionContext = CollisionContext.of(aom);
    }
    
    public Vec3 getTo() {
        return this.to;
    }
    
    public Vec3 getFrom() {
        return this.from;
    }
    
    public VoxelShape getBlockShape(final BlockState cfj, final BlockGetter bpg, final BlockPos fu) {
        return this.block.get(cfj, bpg, fu, this.collisionContext);
    }
    
    public VoxelShape getFluidShape(final FluidState cxa, final BlockGetter bpg, final BlockPos fu) {
        return this.fluid.canPick(cxa) ? cxa.getShape(bpg, fu) : Shapes.empty();
    }
    
    public enum Block implements ShapeGetter {
        COLLIDER(BlockBehaviour.BlockStateBase::getCollisionShape), 
        OUTLINE(BlockBehaviour.BlockStateBase::getShape), 
        VISUAL(BlockBehaviour.BlockStateBase::getVisualShape);
        
        private final ShapeGetter shapeGetter;
        
        private Block(final ShapeGetter c) {
            this.shapeGetter = c;
        }
        
        @Override
        public VoxelShape get(final BlockState cfj, final BlockGetter bpg, final BlockPos fu, final CollisionContext der) {
            return this.shapeGetter.get(cfj, bpg, fu, der);
        }
    }
    
    public enum Fluid {
        NONE(cxa -> false), 
        SOURCE_ONLY(FluidState::isSource), 
        ANY(cxa -> !cxa.isEmpty());
        
        private final Predicate<FluidState> canPick;
        
        private Fluid(final Predicate<FluidState> predicate) {
            this.canPick = predicate;
        }
        
        public boolean canPick(final FluidState cxa) {
            return this.canPick.test(cxa);
        }
    }
    
    public interface ShapeGetter {
        VoxelShape get(final BlockState cfj, final BlockGetter bpg, final BlockPos fu, final CollisionContext der);
    }
}
