// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.npc.commands;

import it.unimi.dsi.fastutil.Pair;
import java.util.List;
import java.util.logging.Level;
import com.hypixel.hytale.server.core.entity.Frozen;
import com.hypixel.hytale.server.core.entity.nameplate.Nameplate;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.function.consumer.TriConsumer;
import com.hypixel.hytale.server.core.asset.type.model.config.Model;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.server.npc.util.NPCPhysicsMath;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.server.npc.NPCPlugin;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.codec.validation.Validator;
import com.hypixel.hytale.codec.validation.Validators;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgumentType;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes;
import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;

public class NPCAllCommand extends AbstractPlayerCommand
{
    @Nonnull
    private static final Message MESSAGE_COMMANDS_NPC_ALL_NO_ROLES_TO_SPAWN;
    @Nonnull
    private final OptionalArg<Double> distanceArg;
    
    public NPCAllCommand() {
        super("all", "server.commands.npc.all.desc", true);
        this.distanceArg = this.withOptionalArg("distance", "server.commands.npc.all.distance", ArgTypes.DOUBLE).addValidator((Validator<Double>)Validators.greaterThan((DataType)0.0));
    }
    
    @Override
    protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
        final double distance = this.distanceArg.provided(context) ? this.distanceArg.get(context) : 4.0;
        final NPCPlugin npcModule = NPCPlugin.get();
        final List<String> roles = npcModule.getRoleTemplateNames(true);
        if (roles.isEmpty()) {
            playerRef.sendMessage(NPCAllCommand.MESSAGE_COMMANDS_NPC_ALL_NO_ROLES_TO_SPAWN);
            return;
        }
        roles.sort(String::compareToIgnoreCase);
        final int columns = MathUtil.ceil(Math.sqrt(roles.size()));
        final double squareSideLength = (columns - 1) * distance;
        final double squareSideLengthHalf = squareSideLength / 2.0;
        final TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType());
        assert transformComponent != null;
        final Vector3d position = transformComponent.getPosition();
        final double px = position.getX() - squareSideLengthHalf;
        final double pz = position.getZ() - squareSideLengthHalf;
        final Vector3d pos = new Vector3d();
        for (int index = 0; index < roles.size(); ++index) {
            final String name = roles.get(index);
            if (name != null) {
                if (!name.isEmpty()) {
                    try {
                        final double x = px + distance * (index % columns);
                        final double z = pz + distance * (index / columns);
                        final double y = NPCPhysicsMath.heightOverGround(world, x, z);
                        if (y >= 0.0) {
                            pos.assign(x, y, z);
                            final int roleIndex = npcModule.getIndex(name);
                            if (roleIndex < 0) {
                                throw new IllegalStateException("No such valid role: " + name);
                            }
                            final Pair<Ref<EntityStore>, NPCEntity> npcPair = npcModule.spawnEntity(store, roleIndex, pos, null, null, null);
                            final Ref<EntityStore> npcRef = npcPair.first();
                            assert npcRef != null;
                            store.putComponent(npcRef, Nameplate.getComponentType(), new Nameplate(name));
                            store.ensureComponent(npcRef, Frozen.getComponentType());
                        }
                    }
                    catch (final Throwable t) {
                        playerRef.sendMessage(Message.translation("server.commands.npc.all.failedToSpawn").param("role", name));
                        npcModule.getLogger().at(Level.WARNING).log("Error spawning NPC with role: %s", name, t);
                    }
                }
            }
        }
    }
    
    static {
        MESSAGE_COMMANDS_NPC_ALL_NO_ROLES_TO_SPAWN = Message.translation("server.commands.npc.all.noRolesToSpawn");
    }
}
