package net.minecraft.world.level.block;

import net.minecraft.world.level.block.state.StateHolder;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.pathfinder.PathComputationType;
import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BedBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.material.PushReaction;
import java.util.function.Predicate;
import java.util.Optional;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.item.BlockPlaceContext;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.phys.Vec3;
import java.util.List;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.level.ExplosionDamageCalculator;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import javax.annotation.Nullable;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.BedPart;
import net.minecraft.world.level.block.state.properties.EnumProperty;

public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock {
    public static final EnumProperty<BedPart> PART;
    public static final BooleanProperty OCCUPIED;
    protected static final VoxelShape BASE;
    protected static final VoxelShape LEG_NORTH_WEST;
    protected static final VoxelShape LEG_SOUTH_WEST;
    protected static final VoxelShape LEG_NORTH_EAST;
    protected static final VoxelShape LEG_SOUTH_EAST;
    protected static final VoxelShape NORTH_SHAPE;
    protected static final VoxelShape SOUTH_SHAPE;
    protected static final VoxelShape WEST_SHAPE;
    protected static final VoxelShape EAST_SHAPE;
    private final DyeColor color;
    
    public BedBlock(final DyeColor bje, final Properties c) {
        super(c);
        this.color = bje;
        this.registerDefaultState((((StateHolder<O, BlockState>)this.stateDefinition.any()).setValue(BedBlock.PART, BedPart.FOOT)).<Comparable, Boolean>setValue((Property<Comparable>)BedBlock.OCCUPIED, false));
    }
    
    @Nullable
    public static Direction getBedOrientation(final BlockGetter bpg, final BlockPos fu) {
        final BlockState cfj3 = bpg.getBlockState(fu);
        return (cfj3.getBlock() instanceof BedBlock) ? cfj3.<Direction>getValue((Property<Direction>)BedBlock.FACING) : null;
    }
    
    @Override
    public InteractionResult use(BlockState cfj, final Level bqb, BlockPos fu, final Player bec, final InteractionHand anf, final BlockHitResult deh) {
        if (bqb.isClientSide) {
            return InteractionResult.CONSUME;
        }
        if (cfj.<BedPart>getValue(BedBlock.PART) != BedPart.HEAD) {
            fu = fu.relative(cfj.<Direction>getValue((Property<Direction>)BedBlock.FACING));
            cfj = bqb.getBlockState(fu);
            if (!cfj.is(this)) {
                return InteractionResult.CONSUME;
            }
        }
        if (!canSetSpawn(bqb)) {
            bqb.removeBlock(fu, false);
            final BlockPos fu2 = fu.relative(cfj.<Direction>getValue((Property<Direction>)BedBlock.FACING).getOpposite());
            if (bqb.getBlockState(fu2).is(this)) {
                bqb.removeBlock(fu2, false);
            }
            bqb.explode(null, DamageSource.badRespawnPointExplosion(), null, fu.getX() + 0.5, fu.getY() + 0.5, fu.getZ() + 0.5, 5.0f, true, Explosion.BlockInteraction.DESTROY);
            return InteractionResult.SUCCESS;
        }
        if (cfj.<Boolean>getValue((Property<Boolean>)BedBlock.OCCUPIED)) {
            if (!this.kickVillagerOutOfBed(bqb, fu)) {
                bec.displayClientMessage(new TranslatableComponent("block.minecraft.bed.occupied"), true);
            }
            return InteractionResult.SUCCESS;
        }
        bec.startSleepInBed(fu).ifLeft(a -> {
            if (a != null) {
                bec.displayClientMessage(a.getMessage(), true);
            }
            return;
        });
        return InteractionResult.SUCCESS;
    }
    
    public static boolean canSetSpawn(final Level bqb) {
        return bqb.dimensionType().bedWorks();
    }
    
    private boolean kickVillagerOutOfBed(final Level bqb, final BlockPos fu) {
        final List<Villager> list4 = bqb.<Villager>getEntitiesOfClass(Villager.class, new AABB(fu), LivingEntity::isSleeping);
        if (list4.isEmpty()) {
            return false;
        }
        list4.get(0).stopSleeping();
        return true;
    }
    
    @Override
    public void fallOn(final Level bqb, final BlockPos fu, final Entity aom, final float float4) {
        super.fallOn(bqb, fu, aom, float4 * 0.5f);
    }
    
    @Override
    public void updateEntityAfterFallOn(final BlockGetter bpg, final Entity aom) {
        if (aom.isSuppressingBounce()) {
            super.updateEntityAfterFallOn(bpg, aom);
        }
        else {
            this.bounceUp(aom);
        }
    }
    
    private void bounceUp(final Entity aom) {
        final Vec3 dem3 = aom.getDeltaMovement();
        if (dem3.y < 0.0) {
            final double double4 = (aom instanceof LivingEntity) ? 1.0 : 0.8;
            aom.setDeltaMovement(dem3.x, -dem3.y * 0.6600000262260437 * double4, dem3.z);
        }
    }
    
    @Override
    public BlockState updateShape(final BlockState cfj1, final Direction fz, final BlockState cfj3, final LevelAccessor bqc, final BlockPos fu5, final BlockPos fu6) {
        if (fz != getNeighbourDirection(cfj1.<BedPart>getValue(BedBlock.PART), cfj1.<Direction>getValue((Property<Direction>)BedBlock.FACING))) {
            return super.updateShape(cfj1, fz, cfj3, bqc, fu5, fu6);
        }
        if (cfj3.is(this) && cfj3.<BedPart>getValue(BedBlock.PART) != cfj1.<BedPart>getValue(BedBlock.PART)) {
            return ((StateHolder<O, BlockState>)cfj1).<Comparable, Comparable>setValue((Property<Comparable>)BedBlock.OCCUPIED, (Comparable)cfj3.<V>getValue((Property<V>)BedBlock.OCCUPIED));
        }
        return Blocks.AIR.defaultBlockState();
    }
    
    private static Direction getNeighbourDirection(final BedPart cfx, final Direction fz) {
        return (cfx == BedPart.FOOT) ? fz : fz.getOpposite();
    }
    
    @Override
    public void playerWillDestroy(final Level bqb, final BlockPos fu, final BlockState cfj, final Player bec) {
        if (!bqb.isClientSide && bec.isCreative()) {
            final BedPart cfx6 = cfj.<BedPart>getValue(BedBlock.PART);
            if (cfx6 == BedPart.FOOT) {
                final BlockPos fu2 = fu.relative(getNeighbourDirection(cfx6, cfj.<Direction>getValue((Property<Direction>)BedBlock.FACING)));
                final BlockState cfj2 = bqb.getBlockState(fu2);
                if (cfj2.getBlock() == this && cfj2.<BedPart>getValue(BedBlock.PART) == BedPart.HEAD) {
                    bqb.setBlock(fu2, Blocks.AIR.defaultBlockState(), 35);
                    bqb.levelEvent(bec, 2001, fu2, Block.getId(cfj2));
                }
            }
        }
        super.playerWillDestroy(bqb, fu, cfj, bec);
    }
    
    @Nullable
    @Override
    public BlockState getStateForPlacement(final BlockPlaceContext bin) {
        final Direction fz3 = bin.getHorizontalDirection();
        final BlockPos fu4 = bin.getClickedPos();
        final BlockPos fu5 = fu4.relative(fz3);
        if (bin.getLevel().getBlockState(fu5).canBeReplaced(bin)) {
            return ((StateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Direction>setValue((Property<Comparable>)BedBlock.FACING, fz3);
        }
        return null;
    }
    
    @Override
    public VoxelShape getShape(final BlockState cfj, final BlockGetter bpg, final BlockPos fu, final CollisionContext der) {
        final Direction fz6 = getConnectedDirection(cfj).getOpposite();
        switch (fz6) {
            case NORTH: {
                return BedBlock.NORTH_SHAPE;
            }
            case SOUTH: {
                return BedBlock.SOUTH_SHAPE;
            }
            case WEST: {
                return BedBlock.WEST_SHAPE;
            }
            default: {
                return BedBlock.EAST_SHAPE;
            }
        }
    }
    
    public static Direction getConnectedDirection(final BlockState cfj) {
        final Direction fz2 = cfj.<Direction>getValue((Property<Direction>)BedBlock.FACING);
        return (cfj.<BedPart>getValue(BedBlock.PART) == BedPart.HEAD) ? fz2.getOpposite() : fz2;
    }
    
    public static DoubleBlockCombiner.BlockType getBlockType(final BlockState cfj) {
        final BedPart cfx2 = cfj.<BedPart>getValue(BedBlock.PART);
        if (cfx2 == BedPart.HEAD) {
            return DoubleBlockCombiner.BlockType.FIRST;
        }
        return DoubleBlockCombiner.BlockType.SECOND;
    }
    
    public static Optional<Vec3> findStandUpPosition(final EntityType<?> aoq, final LevelReader bqd, final BlockPos fu, int integer) {
        final Direction fz5 = bqd.getBlockState(fu).<Direction>getValue((Property<Direction>)BedBlock.FACING);
        final int integer2 = fu.getX();
        final int integer3 = fu.getY();
        final int integer4 = fu.getZ();
        for (int integer5 = 0; integer5 <= 1; ++integer5) {
            final int integer6 = integer2 - fz5.getStepX() * integer5 - 1;
            final int integer7 = integer4 - fz5.getStepZ() * integer5 - 1;
            final int integer8 = integer6 + 2;
            final int integer9 = integer7 + 2;
            for (int integer10 = integer6; integer10 <= integer8; ++integer10) {
                for (int integer11 = integer7; integer11 <= integer9; ++integer11) {
                    final BlockPos fu2 = new BlockPos(integer10, integer3, integer11);
                    final Optional<Vec3> optional17 = getStandingLocationAtOrBelow(aoq, bqd, fu2);
                    if (optional17.isPresent()) {
                        if (integer <= 0) {
                            return optional17;
                        }
                        --integer;
                    }
                }
            }
        }
        return Optional.<Vec3>empty();
    }
    
    public static Optional<Vec3> getStandingLocationAtOrBelow(final EntityType<?> aoq, final LevelReader bqd, final BlockPos fu) {
        final VoxelShape dfg4 = bqd.getBlockState(fu).getCollisionShape(bqd, fu);
        if (dfg4.max(Direction.Axis.Y) > 0.4375) {
            return Optional.<Vec3>empty();
        }
        final BlockPos.MutableBlockPos a5 = fu.mutable();
        while (a5.getY() >= 0 && fu.getY() - a5.getY() <= 2 && bqd.getBlockState(a5).getCollisionShape(bqd, a5).isEmpty()) {
            a5.move(Direction.DOWN);
        }
        final VoxelShape dfg5 = bqd.getBlockState(a5).getCollisionShape(bqd, a5);
        if (dfg5.isEmpty()) {
            return Optional.<Vec3>empty();
        }
        final double double7 = a5.getY() + dfg5.max(Direction.Axis.Y) + 2.0E-7;
        if (fu.getY() - double7 > 2.0) {
            return Optional.<Vec3>empty();
        }
        final Vec3 dem9 = new Vec3(a5.getX() + 0.5, double7, a5.getZ() + 0.5);
        final AABB deg10 = aoq.getAABB(dem9.x, dem9.y, dem9.z);
        if (bqd.noCollision(deg10) && bqd.getBlockStates(deg10.expandTowards(0.0, -0.20000000298023224, 0.0)).noneMatch(aoq::isBlockDangerous)) {
            return Optional.<Vec3>of(dem9);
        }
        return Optional.<Vec3>empty();
    }
    
    @Override
    public PushReaction getPistonPushReaction(final BlockState cfj) {
        return PushReaction.DESTROY;
    }
    
    @Override
    public RenderShape getRenderShape(final BlockState cfj) {
        return RenderShape.ENTITYBLOCK_ANIMATED;
    }
    
    @Override
    protected void createBlockStateDefinition(final StateDefinition.Builder<Block, BlockState> a) {
        a.add(BedBlock.FACING, BedBlock.PART, BedBlock.OCCUPIED);
    }
    
    @Override
    public BlockEntity newBlockEntity(final BlockGetter bpg) {
        return new BedBlockEntity(this.color);
    }
    
    @Override
    public void setPlacedBy(final Level bqb, final BlockPos fu, final BlockState cfj, @Nullable final LivingEntity aoy, final ItemStack bki) {
        super.setPlacedBy(bqb, fu, cfj, aoy, bki);
        if (!bqb.isClientSide) {
            final BlockPos fu2 = fu.relative(cfj.<Direction>getValue((Property<Direction>)BedBlock.FACING));
            bqb.setBlock(fu2, ((StateHolder<O, BlockState>)cfj).<BedPart, BedPart>setValue(BedBlock.PART, BedPart.HEAD), 3);
            bqb.blockUpdated(fu, Blocks.AIR);
            cfj.updateNeighbourShapes(bqb, fu, 3);
        }
    }
    
    public DyeColor getColor() {
        return this.color;
    }
    
    @Override
    public long getSeed(final BlockState cfj, final BlockPos fu) {
        final BlockPos fu2 = fu.relative((Direction)cfj.<Direction>getValue((Property<Direction>)BedBlock.FACING), (int)((cfj.<BedPart>getValue(BedBlock.PART) != BedPart.HEAD) ? 1 : 0));
        return Mth.getSeed(fu2.getX(), fu.getY(), fu2.getZ());
    }
    
    @Override
    public boolean isPathfindable(final BlockState cfj, final BlockGetter bpg, final BlockPos fu, final PathComputationType czg) {
        return false;
    }
    
    static {
        PART = BlockStateProperties.BED_PART;
        OCCUPIED = BlockStateProperties.OCCUPIED;
        BASE = Block.box(0.0, 3.0, 0.0, 16.0, 9.0, 16.0);
        LEG_NORTH_WEST = Block.box(0.0, 0.0, 0.0, 3.0, 3.0, 3.0);
        LEG_SOUTH_WEST = Block.box(0.0, 0.0, 13.0, 3.0, 3.0, 16.0);
        LEG_NORTH_EAST = Block.box(13.0, 0.0, 0.0, 16.0, 3.0, 3.0);
        LEG_SOUTH_EAST = Block.box(13.0, 0.0, 13.0, 16.0, 3.0, 16.0);
        NORTH_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_NORTH_WEST, BedBlock.LEG_NORTH_EAST);
        SOUTH_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_SOUTH_WEST, BedBlock.LEG_SOUTH_EAST);
        WEST_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_NORTH_WEST, BedBlock.LEG_SOUTH_WEST);
        EAST_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_NORTH_EAST, BedBlock.LEG_SOUTH_EAST);
    }
}
