package net.minecraft.server.commands;

import com.mojang.brigadier.CommandDispatcher;
import java.util.Collection;
import java.util.Collections;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.AngleArgument;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;

public class SetSpawnCommand {
    public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
        dispatcher.register(
            Commands.literal("spawnpoint")
                .requires(Commands.hasPermission(2))
                .executes(
                    commandContext -> setSpawn(
                        commandContext.getSource(),
                        Collections.singleton(commandContext.getSource().getPlayerOrException()),
                        BlockPos.containing(commandContext.getSource().getPosition()),
                        0.0F
                    )
                )
                .then(
                    Commands.argument("targets", EntityArgument.players())
                        .executes(
                            context -> setSpawn(
                                context.getSource(),
                                EntityArgument.getPlayers(context, "targets"),
                                BlockPos.containing(context.getSource().getPosition()),
                                0.0F
                            )
                        )
                        .then(
                            Commands.argument("pos", BlockPosArgument.blockPos())
                                .executes(
                                    context -> setSpawn(
                                        context.getSource(),
                                        EntityArgument.getPlayers(context, "targets"),
                                        BlockPosArgument.getSpawnablePos(context, "pos"),
                                        0.0F
                                    )
                                )
                                .then(
                                    Commands.argument("angle", AngleArgument.angle())
                                        .executes(
                                            context -> setSpawn(
                                                context.getSource(),
                                                EntityArgument.getPlayers(context, "targets"),
                                                BlockPosArgument.getSpawnablePos(context, "pos"),
                                                AngleArgument.getAngle(context, "angle")
                                            )
                                        )
                                )
                        )
                )
        );
    }

    private static int setSpawn(CommandSourceStack source, Collection<ServerPlayer> targets, BlockPos pos, float angle) {
        ResourceKey<Level> resourceKey = source.getLevel().dimension();

        final Collection<ServerPlayer> actualTargets = new java.util.ArrayList<>(); // Paper - Add PlayerSetSpawnEvent
        for (ServerPlayer serverPlayer : targets) {
            // Paper start - Add PlayerSetSpawnEvent
            // Folia start - region threading
            serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> {
                player.setRespawnPosition(new ServerPlayer.RespawnConfig(resourceKey, pos, angle, true), false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.COMMAND);
            }, null, 1L);
            if (true) { // Folia end - region threading
                actualTargets.add(serverPlayer);
            }
            // Paper end - Add PlayerSetSpawnEvent
        }
        // Paper start - Add PlayerSetSpawnEvent
        if (actualTargets.isEmpty()) {
            return 0;
        }
        // Paper end - Add PlayerSetSpawnEvent

        String string = resourceKey.location().toString();
        if (actualTargets.size() == 1) { // Paper - Add PlayerSetSpawnEvent
            source.sendSuccess(
                () -> Component.translatable(
                    "commands.spawnpoint.success.single", pos.getX(), pos.getY(), pos.getZ(), angle, string, actualTargets.iterator().next().getDisplayName() // Paper - Add PlayerSetSpawnEvent
                ),
                true
            );
        } else {
            source.sendSuccess(
                () -> Component.translatable("commands.spawnpoint.success.multiple", pos.getX(), pos.getY(), pos.getZ(), angle, string, actualTargets.size()), true // Paper - Add PlayerSetSpawnEvent
            );
        }

        return actualTargets.size(); // Paper - Add PlayerSetSpawnEvent
    }
}
