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

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

import com.hypixel.hytale.server.core.command.system.arguments.system.Argument;
import it.unimi.dsi.fastutil.ints.IntCollection;
import com.hypixel.hytale.component.ComponentType;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import java.util.UUID;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.ints.IntList;
import com.hypixel.hytale.component.Component;
import java.util.logging.Level;
import it.unimi.dsi.fastutil.Pair;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
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 javax.annotation.Nullable;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.server.core.entity.group.EntityGroup;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.server.flock.FlockPlugin;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.npc.NPCPlugin;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
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.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.FlagArg;
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 NPCRunTestsCommand extends AbstractPlayerCommand
{
    @Nonnull
    private static final Message MESSAGE_COMMANDS_NPC_RUN_TESTS_SPECIFY_ROLES;
    @Nonnull
    private final OptionalArg<String> rolesArg;
    @Nonnull
    private final FlagArg presetArg;
    @Nonnull
    private final FlagArg passArg;
    @Nonnull
    private final FlagArg failArg;
    @Nonnull
    private final FlagArg abortArg;
    
    public NPCRunTestsCommand() {
        super("runtests", "server.commands.npc.runtests.desc");
        this.rolesArg = this.withOptionalArg("roles", "server.commands.npc.runtests.roles.desc", ArgTypes.STRING);
        this.presetArg = this.withFlagArg("preset", "server.commands.npc.runtests.preset.desc");
        this.passArg = this.withFlagArg("pass", "server.commands.npc.runtests.pass.desc");
        this.failArg = this.withFlagArg("fail", "server.commands.npc.runtests.fail.desc");
        this.abortArg = this.withFlagArg("abort", "server.commands.npc.runtests.abort.desc");
    }
    
    @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 NPCTestData testDataComponent = store.ensureAndGetComponent(ref, NPCTestData.getComponentType());
        final TransformComponent playerTransformComponent = store.getComponent(ref, TransformComponent.getComponentType());
        assert playerTransformComponent != null;
        if (!testDataComponent.npcRoles.isEmpty()) {
            if (((Argument<Arg, Boolean>)this.passArg).get(context)) {
                setNextRole(testDataComponent, ref, store, world);
                return;
            }
            if (((Argument<Arg, Boolean>)this.failArg).get(context)) {
                testDataComponent.failedRoles.add(testDataComponent.npcRoles.getInt(testDataComponent.index));
                setNextRole(testDataComponent, ref, store, world);
                return;
            }
            if (((Argument<Arg, Boolean>)this.abortArg).get(context)) {
                reportResults(ref, testDataComponent, store);
                final Ref<EntityStore> npcRef = world.getEntityRef(testDataComponent.targetUUID);
                if (npcRef != null) {
                    cleanupNPC(npcRef, store);
                }
                store.removeComponent(ref, NPCTestData.getComponentType());
                return;
            }
        }
        String[] roles;
        if (((Argument<Arg, Boolean>)this.presetArg).get(context)) {
            roles = NPCPlugin.get().getPresetCoverageTestNPCs();
        }
        else {
            if (!this.rolesArg.provided(context)) {
                context.sendMessage(NPCRunTestsCommand.MESSAGE_COMMANDS_NPC_RUN_TESTS_SPECIFY_ROLES);
                store.removeComponent(ref, NPCTestData.getComponentType());
                return;
            }
            final String roleString = this.rolesArg.get(context);
            if (roleString == null || roleString.isEmpty()) {
                context.sendMessage(NPCRunTestsCommand.MESSAGE_COMMANDS_NPC_RUN_TESTS_SPECIFY_ROLES);
                store.removeComponent(ref, NPCTestData.getComponentType());
                return;
            }
            roles = roleString.split(",");
        }
        for (String role : roles) {
            Label_0459: {
                int flockSize;
                try {
                    final int idx = role.indexOf(35);
                    flockSize = ((idx < 0) ? 1 : Integer.parseInt(role.substring(idx + 1)));
                    if (idx > 0) {
                        role = role.substring(0, idx);
                    }
                }
                catch (final NumberFormatException e) {
                    context.sendMessage(Message.translation("server.commands.npc.runtests.invalidflocksize").param("role", role));
                    break Label_0459;
                }
                final int builderIndex = NPCPlugin.get().getIndex(role);
                if (builderIndex == Integer.MIN_VALUE) {
                    context.sendMessage(Message.translation("server.commands.npc.spawn.templateNotFound").param("template", role));
                }
                else {
                    testDataComponent.npcRoles.add(builderIndex);
                    testDataComponent.flockSizes.add(flockSize);
                }
            }
        }
        if (testDataComponent.targetUUID == null) {
            spawnNPC(ref, testDataComponent, 0, playerTransformComponent.getPosition(), playerTransformComponent.getRotation(), store);
        }
    }
    
    private static void setNextRole(@Nonnull final NPCTestData testData, @Nonnull final Ref<EntityStore> reference, @Nonnull final Store<EntityStore> store, @Nonnull final World world) {
        final Ref<EntityStore> npcReference = world.getEntityRef(testData.targetUUID);
        ++testData.index;
        if (testData.index >= testData.npcRoles.size()) {
            reportResults(reference, testData, store);
            if (npcReference != null) {
                cleanupNPC(npcReference, store);
            }
            store.removeComponent(reference, NPCTestData.getComponentType());
            return;
        }
        Vector3d position;
        Vector3f rotation;
        if (npcReference != null) {
            final TransformComponent npcTransformComponent = store.getComponent(npcReference, TransformComponent.getComponentType());
            assert npcTransformComponent != null;
            position = npcTransformComponent.getPosition();
            rotation = npcTransformComponent.getRotation();
            cleanupNPC(npcReference, store);
        }
        else {
            final TransformComponent transformComponent = store.getComponent(reference, TransformComponent.getComponentType());
            assert transformComponent != null;
            position = transformComponent.getPosition();
            rotation = transformComponent.getRotation();
        }
        spawnNPC(reference, testData, testData.index, position, rotation, store);
    }
    
    private static void cleanupNPC(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store) {
        final Ref<EntityStore> flockReference = FlockPlugin.getFlockReference(ref, store);
        if (flockReference != null) {
            final ObjectArrayList<Ref<EntityStore>> members = new ObjectArrayList<Ref<EntityStore>>();
            final EntityGroup entityGroupComponent = store.getComponent(flockReference, EntityGroup.getComponentType());
            assert entityGroupComponent != null;
            Ref<EntityStore> member = null;
            entityGroupComponent.forEachMember((index, member, list) -> list.add(member), members);
            final ObjectListIterator<Object> iterator = members.iterator();
            while (iterator.hasNext()) {
                member = iterator.next();
                store.removeEntity(member, RemoveReason.REMOVE);
            }
        }
        store.removeEntity(ref, RemoveReason.REMOVE);
    }
    
    private static void spawnNPC(@Nonnull final Ref<EntityStore> playerReference, @Nonnull final NPCTestData testData, final int index, @Nonnull final Vector3d position, @Nullable final Vector3f rotation, @Nonnull final Store<EntityStore> store) {
        final Pair<Ref<EntityStore>, NPCEntity> npcPair = NPCPlugin.get().spawnEntity(store, testData.npcRoles.getInt(index), position, rotation, null, null);
        final Ref<EntityStore> npcRef = npcPair.first();
        final NPCEntity npcComponent = npcPair.second();
        final int flockSize = testData.flockSizes.getInt(index);
        if (flockSize > 1) {
            final TransformComponent npcTransformComponent = store.getComponent(npcRef, TransformComponent.getComponentType());
            assert npcTransformComponent != null;
            FlockPlugin.trySpawnFlock(npcRef, npcComponent, store, npcComponent.getRoleIndex(), npcTransformComponent.getPosition(), npcTransformComponent.getRotation(), flockSize, null);
        }
        final String roleName = npcComponent.getRoleName();
        final PlayerRef playerRefComponent = store.getComponent(playerReference, PlayerRef.getComponentType());
        assert playerRefComponent != null;
        playerRefComponent.sendMessage(Message.translation("server.commands.npc.runtests.testing").param("role", roleName).insert("\n").insert(Message.translation("server.npc.tests." + roleName)));
        final UUIDComponent npcUUIDComponent = store.getComponent(npcRef, UUIDComponent.getComponentType());
        assert npcUUIDComponent != null;
        testData.targetUUID = npcUUIDComponent.getUuid();
    }
    
    private static void reportResults(@Nonnull final Ref<EntityStore> playerReference, @Nonnull final NPCTestData testData, @Nonnull final Store<EntityStore> store) {
        final NPCPlugin npcPlugin = NPCPlugin.get();
        final Message msg = Message.translation("server.commands.npc.runtests.results");
        for (int i = 0; i < testData.npcRoles.size(); ++i) {
            final int index = testData.npcRoles.getInt(i);
            msg.insert("  " + npcPlugin.getName(index) + ": ");
            final String result = (i >= testData.index) ? "server.commands.npc.runtests.notrun" : (testData.failedRoles.contains(index) ? "server.commands.npc.runtests.fail" : "server.commands.npc.runtests.pass");
            msg.insert(Message.translation(result));
            msg.insert("\n");
        }
        final PlayerRef playerRef = store.getComponent(playerReference, PlayerRef.getComponentType());
        assert playerRef != null;
        playerRef.sendMessage(msg);
        npcPlugin.getLogger().at(Level.INFO).log(msg.getRawText());
    }
    
    static {
        MESSAGE_COMMANDS_NPC_RUN_TESTS_SPECIFY_ROLES = Message.translation("server.commands.npc.runtests.specifyroles");
    }
    
    public static class NPCTestData implements Component<EntityStore>
    {
        private final IntList npcRoles;
        private final IntList flockSizes;
        private final IntSet failedRoles;
        private int index;
        private UUID targetUUID;
        
        public NPCTestData() {
            this.npcRoles = new IntArrayList();
            this.flockSizes = new IntArrayList();
            this.failedRoles = new IntOpenHashSet();
        }
        
        public static ComponentType<EntityStore, NPCTestData> getComponentType() {
            return NPCPlugin.get().getNpcTestDataComponentType();
        }
        
        @Nonnull
        @Override
        public Component<EntityStore> clone() {
            final NPCTestData data = new NPCTestData();
            data.npcRoles.addAll(this.npcRoles);
            data.index = this.index;
            data.failedRoles.addAll(this.failedRoles);
            return data;
        }
    }
}
