package net.minecraft.world.level.block;

import net.minecraft.world.level.block.state.AbstractStateHolder;
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.level.block.entity.BedBlockEntity;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.material.PushReaction;
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.stats.Stat;
import net.minecraft.stats.Stats;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
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.entity.Entity;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.level.biome.Biomes;
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.world.level.material.MaterialColor;
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.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 bdj, final Properties c) {
        super(c);
        this.color = bdj;
        this.registerDefaultState((((AbstractStateHolder<O, BlockState>)this.stateDefinition.any()).setValue(BedBlock.PART, BedPart.FOOT)).<Comparable, Boolean>setValue((Property<Comparable>)BedBlock.OCCUPIED, false));
    }
    
    @Override
    public MaterialColor getMapColor(final BlockState byj, final BlockGetter bjg, final BlockPos fk) {
        if (byj.<BedPart>getValue(BedBlock.PART) == BedPart.FOOT) {
            return this.color.getMaterialColor();
        }
        return MaterialColor.WOOL;
    }
    
    @Nullable
    public static Direction getBedOrientation(final BlockGetter bjg, final BlockPos fk) {
        final BlockState byj3 = bjg.getBlockState(fk);
        return (byj3.getBlock() instanceof BedBlock) ? byj3.<Direction>getValue((Property<Direction>)BedBlock.FACING) : null;
    }
    
    @Override
    public InteractionResult use(BlockState byj, final Level bjw, BlockPos fk, final Player ayj, final InteractionHand ajk, final BlockHitResult cvg) {
        if (bjw.isClientSide) {
            return InteractionResult.CONSUME;
        }
        if (byj.<BedPart>getValue(BedBlock.PART) != BedPart.HEAD) {
            fk = fk.relative(byj.<Direction>getValue((Property<Direction>)BedBlock.FACING));
            byj = bjw.getBlockState(fk);
            if (byj.getBlock() != this) {
                return InteractionResult.CONSUME;
            }
        }
        if (!bjw.dimension.mayRespawn() || bjw.getBiome(fk) == Biomes.NETHER) {
            bjw.removeBlock(fk, false);
            final BlockPos fk2 = fk.relative(byj.<Direction>getValue((Property<Direction>)BedBlock.FACING).getOpposite());
            if (bjw.getBlockState(fk2).getBlock() == this) {
                bjw.removeBlock(fk2, false);
            }
            bjw.explode(null, DamageSource.netherBedExplosion(), fk.getX() + 0.5, fk.getY() + 0.5, fk.getZ() + 0.5, 5.0f, true, Explosion.BlockInteraction.DESTROY);
            return InteractionResult.SUCCESS;
        }
        if (byj.<Boolean>getValue((Property<Boolean>)BedBlock.OCCUPIED)) {
            if (!this.kickVillagerOutOfBed(bjw, fk)) {
                ayj.displayClientMessage(new TranslatableComponent("block.minecraft.bed.occupied", new Object[0]), true);
            }
            return InteractionResult.SUCCESS;
        }
        ayj.startSleepInBed(fk).ifLeft(a -> {
            if (a != null) {
                ayj.displayClientMessage(a.getMessage(), true);
            }
            return;
        });
        return InteractionResult.SUCCESS;
    }
    
    private boolean kickVillagerOutOfBed(final Level bjw, final BlockPos fk) {
        final List<Villager> list4 = bjw.<Villager>getEntitiesOfClass(Villager.class, new AABB(fk), LivingEntity::isSleeping);
        if (list4.isEmpty()) {
            return false;
        }
        list4.get(0).stopSleeping();
        return true;
    }
    
    @Override
    public void fallOn(final Level bjw, final BlockPos fk, final Entity akq, final float float4) {
        super.fallOn(bjw, fk, akq, float4 * 0.5f);
    }
    
    @Override
    public void updateEntityAfterFallOn(final BlockGetter bjg, final Entity akq) {
        if (akq.isSuppressingBounce()) {
            super.updateEntityAfterFallOn(bjg, akq);
        }
        else {
            this.bounceUp(akq);
        }
    }
    
    private void bounceUp(final Entity akq) {
        final Vec3 cvl3 = akq.getDeltaMovement();
        if (cvl3.y < 0.0) {
            final double double4 = (akq instanceof LivingEntity) ? 1.0 : 0.8;
            akq.setDeltaMovement(cvl3.x, -cvl3.y * 0.6600000262260437 * double4, cvl3.z);
        }
    }
    
    @Override
    public BlockState updateShape(final BlockState byj1, final Direction fp, final BlockState byj3, final LevelAccessor bjx, final BlockPos fk5, final BlockPos fk6) {
        if (fp != getNeighbourDirection(byj1.<BedPart>getValue(BedBlock.PART), byj1.<Direction>getValue((Property<Direction>)BedBlock.FACING))) {
            return super.updateShape(byj1, fp, byj3, bjx, fk5, fk6);
        }
        if (byj3.getBlock() == this && byj3.<BedPart>getValue(BedBlock.PART) != byj1.<BedPart>getValue(BedBlock.PART)) {
            return ((AbstractStateHolder<O, BlockState>)byj1).<Comparable, Comparable>setValue((Property<Comparable>)BedBlock.OCCUPIED, (Comparable)byj3.<V>getValue((Property<V>)BedBlock.OCCUPIED));
        }
        return Blocks.AIR.defaultBlockState();
    }
    
    private static Direction getNeighbourDirection(final BedPart byy, final Direction fp) {
        return (byy == BedPart.FOOT) ? fp : fp.getOpposite();
    }
    
    @Override
    public void playerDestroy(final Level bjw, final Player ayj, final BlockPos fk, final BlockState byj, @Nullable final BlockEntity bwl, final ItemStack ben) {
        super.playerDestroy(bjw, ayj, fk, Blocks.AIR.defaultBlockState(), bwl, ben);
    }
    
    @Override
    public void playerWillDestroy(final Level bjw, final BlockPos fk, final BlockState byj, final Player ayj) {
        final BedPart byy6 = byj.<BedPart>getValue(BedBlock.PART);
        final BlockPos fk2 = fk.relative(getNeighbourDirection(byy6, byj.<Direction>getValue((Property<Direction>)BedBlock.FACING)));
        final BlockState byj2 = bjw.getBlockState(fk2);
        if (byj2.getBlock() == this && byj2.<BedPart>getValue(BedBlock.PART) != byy6) {
            bjw.setBlock(fk2, Blocks.AIR.defaultBlockState(), 35);
            bjw.levelEvent(ayj, 2001, fk2, Block.getId(byj2));
            if (!bjw.isClientSide && !ayj.isCreative()) {
                final ItemStack ben9 = ayj.getMainHandItem();
                Block.dropResources(byj, bjw, fk, null, ayj, ben9);
                Block.dropResources(byj2, bjw, fk2, null, ayj, ben9);
            }
            ayj.awardStat(Stats.BLOCK_MINED.get(this));
        }
        super.playerWillDestroy(bjw, fk, byj, ayj);
    }
    
    @Nullable
    @Override
    public BlockState getStateForPlacement(final BlockPlaceContext bcq) {
        final Direction fp3 = bcq.getHorizontalDirection();
        final BlockPos fk4 = bcq.getClickedPos();
        final BlockPos fk5 = fk4.relative(fp3);
        if (bcq.getLevel().getBlockState(fk5).canBeReplaced(bcq)) {
            return ((AbstractStateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Direction>setValue((Property<Comparable>)BedBlock.FACING, fp3);
        }
        return null;
    }
    
    @Override
    public VoxelShape getShape(final BlockState byj, final BlockGetter bjg, final BlockPos fk, final CollisionContext cvq) {
        final Direction fp6 = getConnectedDirection(byj).getOpposite();
        switch (fp6) {
            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 byj) {
        final Direction fp2 = byj.<Direction>getValue((Property<Direction>)BedBlock.FACING);
        return (byj.<BedPart>getValue(BedBlock.PART) == BedPart.HEAD) ? fp2.getOpposite() : fp2;
    }
    
    public static DoubleBlockCombiner.BlockType getBlockType(final BlockState byj) {
        final BedPart byy2 = byj.<BedPart>getValue(BedBlock.PART);
        if (byy2 == BedPart.HEAD) {
            return DoubleBlockCombiner.BlockType.FIRST;
        }
        return DoubleBlockCombiner.BlockType.SECOND;
    }
    
    public static Optional<Vec3> findStandUpPosition(final EntityType<?> aku, final LevelReader bjz, final BlockPos fk, int integer) {
        final Direction fp5 = bjz.getBlockState(fk).<Direction>getValue((Property<Direction>)BedBlock.FACING);
        final int integer2 = fk.getX();
        final int integer3 = fk.getY();
        final int integer4 = fk.getZ();
        for (int integer5 = 0; integer5 <= 1; ++integer5) {
            final int integer6 = integer2 - fp5.getStepX() * integer5 - 1;
            final int integer7 = integer4 - fp5.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 fk2 = new BlockPos(integer10, integer3, integer11);
                    final Optional<Vec3> optional17 = getStandingLocationAtOrBelow(aku, bjz, fk2);
                    if (optional17.isPresent()) {
                        if (integer <= 0) {
                            return optional17;
                        }
                        --integer;
                    }
                }
            }
        }
        return Optional.<Vec3>empty();
    }
    
    protected static Optional<Vec3> getStandingLocationAtOrBelow(final EntityType<?> aku, final LevelReader bjz, final BlockPos fk) {
        final VoxelShape cwf4 = bjz.getBlockState(fk).getCollisionShape(bjz, fk);
        if (cwf4.max(Direction.Axis.Y) > 0.4375) {
            return Optional.<Vec3>empty();
        }
        final BlockPos.MutableBlockPos a5 = new BlockPos.MutableBlockPos(fk);
        while (a5.getY() >= 0 && fk.getY() - a5.getY() <= 2 && bjz.getBlockState(a5).getCollisionShape(bjz, a5).isEmpty()) {
            a5.move(Direction.DOWN);
        }
        final VoxelShape cwf5 = bjz.getBlockState(a5).getCollisionShape(bjz, a5);
        if (cwf5.isEmpty()) {
            return Optional.<Vec3>empty();
        }
        final double double7 = a5.getY() + cwf5.max(Direction.Axis.Y) + 2.0E-7;
        if (fk.getY() - double7 > 2.0) {
            return Optional.<Vec3>empty();
        }
        final float float9 = aku.getWidth() / 2.0f;
        final Vec3 cvl10 = new Vec3(a5.getX() + 0.5, double7, a5.getZ() + 0.5);
        if (bjz.noCollision(new AABB(cvl10.x - float9, cvl10.y, cvl10.z - float9, cvl10.x + float9, cvl10.y + aku.getHeight(), cvl10.z + float9))) {
            return Optional.<Vec3>of(cvl10);
        }
        return Optional.<Vec3>empty();
    }
    
    @Override
    public PushReaction getPistonPushReaction(final BlockState byj) {
        return PushReaction.DESTROY;
    }
    
    @Override
    public RenderShape getRenderShape(final BlockState byj) {
        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 bjg) {
        return new BedBlockEntity(this.color);
    }
    
    @Override
    public void setPlacedBy(final Level bjw, final BlockPos fk, final BlockState byj, @Nullable final LivingEntity akz, final ItemStack ben) {
        super.setPlacedBy(bjw, fk, byj, akz, ben);
        if (!bjw.isClientSide) {
            final BlockPos fk2 = fk.relative(byj.<Direction>getValue((Property<Direction>)BedBlock.FACING));
            bjw.setBlock(fk2, ((AbstractStateHolder<O, BlockState>)byj).<BedPart, BedPart>setValue(BedBlock.PART, BedPart.HEAD), 3);
            bjw.blockUpdated(fk, Blocks.AIR);
            byj.updateNeighbourShapes(bjw, fk, 3);
        }
    }
    
    public DyeColor getColor() {
        return this.color;
    }
    
    @Override
    public long getSeed(final BlockState byj, final BlockPos fk) {
        final BlockPos fk2 = fk.relative((Direction)byj.<Direction>getValue((Property<Direction>)BedBlock.FACING), (int)((byj.<BedPart>getValue(BedBlock.PART) != BedPart.HEAD) ? 1 : 0));
        return Mth.getSeed(fk2.getX(), fk.getY(), fk2.getZ());
    }
    
    @Override
    public boolean isPathfindable(final BlockState byj, final BlockGetter bjg, final BlockPos fk, final PathComputationType cqr) {
        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);
    }
}
