package net.cmr.jurassicrevived.block.custom;

//? if >1.20.1 {
/*import com.mojang.serialization.MapCodec;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.ItemInteractionResult;
*///?}

import dev.architectury.registry.menu.MenuRegistry;
import net.cmr.jurassicrevived.block.entity.ModBlockEntities;
import net.cmr.jurassicrevived.block.entity.custom.IncubatorBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;

public class IncubatorBlock extends BaseEntityBlock {
	public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
	public static final BooleanProperty LIT = BlockStateProperties.LIT;

	//? if >1.20.1 {
	/*public static final MapCodec<IncubatorBlock> CODEC = simpleCodec(IncubatorBlock::new);
	@Override protected MapCodec<? extends BaseEntityBlock> codec() { return CODEC; }
	*///?}

	public IncubatorBlock(Properties properties) {
		super(properties);
	}

	private static final VoxelShape SHAPE = Shapes.box(
		0.0 / 16.0, 0.0 / 16.0, 0.0 / 16.0,
		16.0 / 16.0, 23.0 / 16.0, 16.0 / 16.0
	);

	private static final VoxelShape SHAPE_LIT = Shapes.box(
		0.0 / 16.0, 0.0 / 16.0, 0.0 / 16.0,
		16.0 / 16.0, 18.0 / 16.0, 16.0 / 16.0
	);

	@Override
	public BlockState rotate(BlockState state, Rotation rotation) {
		return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
	}

	@Override
	public BlockState mirror(BlockState state, Mirror mirror) {
		return state.rotate(mirror.getRotation(state.getValue(FACING)));
	}

	@Override
	public @Nullable BlockState getStateForPlacement(BlockPlaceContext context) {
		return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite().getOpposite()).setValue(LIT, false);
	}

	@Override
	protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
		builder.add(FACING, LIT);
	}

	@Override
	public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
		boolean lit = state.getValue(LIT);
		return lit ? SHAPE_LIT : SHAPE;
	}

	@Override
	public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
		return new IncubatorBlockEntity(blockPos, blockState);
	}

	@Override
	public RenderShape getRenderShape(BlockState state) {
		return RenderShape.MODEL;
	}

	@Override
		//? if >1.20.1 {
	/*public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) {
	 *///?} else {
	public void playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) {
		//?}
		if (!level.isClientSide) {
			if (player.getAbilities().instabuild) {
				level.removeBlockEntity(pos);
				level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
				//? if >1.20.1 {
				/*return state;
				 *///?} else {
				return;
				//?}
			}

			BlockEntity be = level.getBlockEntity(pos);
			if (be instanceof IncubatorBlockEntity fbe) {
				ItemStack stack = new ItemStack(this.asItem());

				if (!fbe.isEmptyForDrop()) {
					//? if >1.20.1 {
					/*CompoundTag tag = fbe.saveWithoutMetadata(level.registryAccess());
					var beTypeKey = level.registryAccess().registryOrThrow(Registries.BLOCK_ENTITY_TYPE).getKey(fbe.getType());
					if (beTypeKey != null) tag.putString("id", beTypeKey.toString());
					stack.set(DataComponents.BLOCK_ENTITY_DATA, CustomData.of(tag));
					*///?} else {
					CompoundTag tag = fbe.saveWithoutMetadata();
					stack.getOrCreateTagElement("BlockEntityTag").merge(tag);
					//?}
				}

				popResource(level, pos, stack);
				level.removeBlockEntity(pos);
				level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
				//? if >1.20.1 {
				/*return state;
				 *///?} else {
				return;
				//?}
			}
		}
		super.playerWillDestroy(level, pos, state, player);
		//? if >1.20.1 {
		/*return state;
		 *///?} else {
		return;
		//?}
	}

	@Override
	public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
		super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving);
	}

	//? if >1.20.1 {
	/*@Override
	protected ItemInteractionResult useItemOn(ItemStack pStack, BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pHitResult) {
		if (!pLevel.isClientSide()) {
			BlockEntity entity = pLevel.getBlockEntity(pPos);
			if(entity instanceof IncubatorBlockEntity incubatorBlockEntity) {
				MenuRegistry.openExtendedMenu((ServerPlayer) pPlayer, incubatorBlockEntity);
			}
		}
		return ItemInteractionResult.sidedSuccess(pLevel.isClientSide());
	}
	*///?} else {
	@Override
	public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
		if (!level.isClientSide()) {
			BlockEntity entity = level.getBlockEntity(pos);
			if (entity instanceof IncubatorBlockEntity incubatorBlockEntity) {
				MenuRegistry.openExtendedMenu((ServerPlayer) player, incubatorBlockEntity);
			}
		}
		return InteractionResult.sidedSuccess(level.isClientSide());
	}
	//?}

	@Override
	public @Nullable <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
		if (blockEntityType != ModBlockEntities.INCUBATOR_BE.get()) return null;

		if (level.isClientSide) {
			return null;
		} else {
			return createTickerHelper(blockEntityType, ModBlockEntities.INCUBATOR_BE.get(),
				(level1, blockPos, blockState, incubatorBlockEntity) -> incubatorBlockEntity.tick(level1, blockPos, blockState));
		}
	}

	@Override
	public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
		if (!state.getValue(LIT)) {
			return;
		}

		double xPos = (double)pos.getX() + 0.5;
		double yPos = pos.getY();
		double zPos = (double)pos.getZ() + 0.5;

		Direction direction = state.getValue(FACING).getOpposite();
		Direction.Axis axis = direction.getAxis();

		double defaultOffset = random.nextDouble() * 0.6 - 0.3;
		double xOffsets = axis == Direction.Axis.X ? (double)direction.getStepX() * 0.52 : defaultOffset;
		double yOffset = random.nextDouble() * 6.0 / 8.0;
		double zOffset = axis == Direction.Axis.Z ? (double)direction.getStepZ() * 0.52 : defaultOffset;

		level.addParticle(ParticleTypes.SMOKE, xPos + xOffsets, yPos + yOffset, zPos + zOffset, 0.0, 0.0, 0.0);
	}
}