package top.r3944realms.lib39.content.block;

import com.mojang.authlib.GameProfile;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.ResolvableProfile;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.entity.BlockEntity;
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.EnumProperty;
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
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.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.client.model.IDollPose;
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
import top.r3944realms.lib39.content.block.property.DollPose;
import top.r3944realms.lib39.core.register.Lib39BlockEntities;
import top.r3944realms.lib39.core.register.Lib39Items;
import top.r3944realms.lib39.core.register.Lib39SoundEvents;
import top.r3944realms.lib39.util.GameProfileHelper;

import java.util.List;

/**
 * The type Abstract doll block.
 */
@SuppressWarnings("deprecation")
public abstract class AbstractDollBlock extends BaseEntityBlock implements SimpleWaterloggedBlock {
    /**
     * The constant WATERLOGGED.
     */
    public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
    private static final Properties properties = Properties.of()
            .instrument(NoteBlockInstrument.BASEDRUM)
            .sound(SoundType.WOOL)
            .pushReaction(PushReaction.DESTROY)
            .strength(0f, 10f)
            .noOcclusion();
    private static final double PARTICLE_OFFSET_RANGE = 0.25;
    private static final double PARTICLE_HEIGHT_OFFSET = 1.0;
    private static final double PARTICLE_HEIGHT_VARIANCE = 0.2;
    private static final float NOTE_COLOR_DIVISOR = 24.0F;
    private static final int MAX_NOTE_COLORS = 4;

    private static final float BASE_VOLUME = 1.0f;
    private static final float PITCH_VARIANCE = 0.5f;
    private static final float BASE_PITCH = 0.75f;

    private static final VoxelShape DOLL_SHAPE = Block.box(2.0d, 0.0d, 2.0d, 14.0d, 12.0d, 14.0d);
    /**
     * The constant POSE.
     */
    public static final EnumProperty<DollPose> POSE =  EnumProperty.create("pose", DollPose.class);

    /**
     * Instantiates a new Abstract doll block.
     */
    public AbstractDollBlock() {
        super(properties);
    }
    @Override
    public boolean canBeReplaced(@NotNull BlockState state, @NotNull BlockPlaceContext useContext) {
        return false;
    }

    @Override
    public @NotNull BlockState updateShape(@NotNull BlockState currentState, @NotNull Direction direction, @NotNull BlockState neighborState,
                                           @NotNull LevelAccessor level, @NotNull BlockPos currentPos, @NotNull BlockPos neighborPos) {
        if (currentState.getValue(WATERLOGGED)) {
            level.scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
        }
        return super.updateShape(currentState, direction, neighborState, level, currentPos, neighborPos);
    }

    @Override
    public @NotNull FluidState getFluidState(@NotNull BlockState blockState) {
        return blockState.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(blockState);
    }

    @Override
    protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
        if (level instanceof ServerLevel serverLevel) {
            // 播放粒子效果
            spawnNoteParticles(serverLevel, pos);
            // 播放音效
            playDollSound(serverLevel, pos);
        }
        return InteractionResult.SUCCESS;
    }

    /**
     * 在玩偶位置生成音符粒子效果
     */
    private void spawnNoteParticles(ServerLevel serverLevel, BlockPos blockPos) {
        Vec3 particlePosition = calculateParticlePosition(serverLevel, blockPos);
        float noteColor = calculateNoteColor(serverLevel);

        serverLevel.sendParticles(ParticleTypes.NOTE,
                particlePosition.x(), particlePosition.y(), particlePosition.z(),
                0, noteColor, 0, 0, 1);
    }

    /**
     * 计算粒子生成位置，添加随机偏移
     */
    private @NotNull Vec3 calculateParticlePosition(@NotNull ServerLevel serverLevel, BlockPos blockPos) {
        return Vec3.atBottomCenterOf(blockPos).add(
                (serverLevel.getRandom().nextFloat() - 0.5) * PARTICLE_OFFSET_RANGE * 2,
                PARTICLE_HEIGHT_OFFSET + serverLevel.getRandom().nextFloat() * PARTICLE_HEIGHT_VARIANCE,
                (serverLevel.getRandom().nextFloat() - 0.5) * PARTICLE_OFFSET_RANGE * 2
        );
    }

    /**
     * 计算音符粒子的颜色
     */
    private float calculateNoteColor(@NotNull ServerLevel serverLevel) {
        return serverLevel.getRandom().nextInt(MAX_NOTE_COLORS) / NOTE_COLOR_DIVISOR;
    }

    /**
     * 播放玩偶音效
     */
    private void playDollSound(@NotNull ServerLevel serverLevel, BlockPos blockPos) {
        float pitch = BASE_PITCH + serverLevel.random.nextFloat() * PITCH_VARIANCE;
        serverLevel.playSound(null, blockPos, Lib39SoundEvents.DUCK_TOY.get(),
                SoundSource.BLOCKS, BASE_VOLUME, pitch);
    }

    @Override
    public @NotNull VoxelShape getShape(@NotNull BlockState blockState, @NotNull BlockGetter level, @NotNull BlockPos blockPos, @NotNull CollisionContext context) {
        return DOLL_SHAPE;
    }

    public @NotNull VoxelShape getOcclusionShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos) {
        return Shapes.empty();
    }

    @Nullable
    @Override
    public BlockEntity newBlockEntity(@NotNull BlockPos blockPos, @NotNull BlockState blockState) {
        return Lib39BlockEntities.DOLL_BLOCK_ENTITY.get().create(blockPos, blockState);
    }

    @SuppressWarnings("deprecation")
    @Override
    public @NotNull RenderShape getRenderShape(@NotNull BlockState state) {
        return RenderShape.ENTITYBLOCK_ANIMATED;
    }

    @Override
    public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state) {
        ItemStack stack = super.getCloneItemStack(level, pos, state);
        BlockEntity blockEntity = level.getBlockEntity(pos);
        if (blockEntity instanceof DollBlockEntity doll) {
            ResolvableProfile profile;
            if (doll.getOwnerProfile() != null) {
                profile = doll.getOwnerProfile();
                if (profile != null) {
                    GameProfileHelper.saveProfileToItemStack(stack, profile);
                }
            }
        }
        return stack;
    }

    /**
     * 最重要的方法：重写掉落逻辑
     */
    @Override
    @NotNull
    public List<ItemStack> getDrops(@NotNull BlockState state, @NotNull LootParams.Builder params) {
        // 获取方块实体
        BlockEntity blockEntity = params.getOptionalParameter(LootContextParams.BLOCK_ENTITY);

        if (blockEntity instanceof DollBlockEntity dollEntity) {
            List<ItemStack> customDrops = getCustomDrops(dollEntity, params);
            if (customDrops != null) return customDrops;
        }
        return super.getDrops(state, params);
    }

    @Override
    protected void createBlockStateDefinition(StateDefinition.@NotNull Builder<Block, BlockState> builder) {
        super.createBlockStateDefinition(builder);
        builder.add(WATERLOGGED, POSE);
    }
    @Override
    public void setPlacedBy(@NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState state,
                            @Nullable LivingEntity placer, @NotNull ItemStack stack) {
        super.setPlacedBy(level, pos, state, placer, stack);

        BlockEntity blockEntity = level.getBlockEntity(pos);
        if (blockEntity instanceof DollBlockEntity dollEntity) {
            ResolvableProfile profile = GameProfileHelper.getProfileFromItemStack(stack);
            if (profile != null) {
                dollEntity.setOwner(profile);
            }
        }
    }

    /**
     * 生成自定义掉落物
     */
    @Nullable
    private List<ItemStack> getCustomDrops(DollBlockEntity dollEntity, LootParams.@NotNull Builder params) {
        if (params.getOptionalParameter(LootContextParams.THIS_ENTITY) instanceof Player player) {
            if (player.isCreative()) {
                return List.of();
            }
        }
        ResolvableProfile profile;
        if (dollEntity.getOwnerProfile() != null) {
            profile = dollEntity.getOwnerProfile();
            if (profile != null) {
                ItemStack instance = Lib39Items.DOLL.get().getDefaultInstance();
                GameProfileHelper.saveProfileToItemStack(instance, profile);
                return List.of(instance);
            }
        }
        return null;
    }
}
