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

package com.hypixel.hytale.server.core.command.commands.utility;

import org.bson.BsonDocument;
import java.util.stream.Stream;
import java.util.List;
import java.io.IOException;
import com.hypixel.hytale.sneakythrow.SneakyThrow;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.prefab.selection.buffer.BsonPrefabBufferDeserializer;
import com.hypixel.hytale.server.core.util.BsonUtil;
import java.nio.file.LinkOption;
import java.nio.file.Files;
import com.hypixel.hytale.server.core.util.io.FileUtil;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.nio.file.Path;
import java.util.Iterator;
import com.hypixel.hytale.assetstore.AssetPack;
import com.hypixel.hytale.server.core.asset.AssetModule;
import com.hypixel.hytale.common.util.PathUtil;
import java.util.concurrent.CompletableFuture;
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 javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractAsyncCommand;

public class ValidateCPBCommand extends AbstractAsyncCommand
{
    private static final String UNABLE_TO_LOAD_MODEL = "Unable to load entity with model ";
    private static final String FAILED_TO_FIND_BLOCK = "Failed to find block ";
    @Nonnull
    private final OptionalArg<String> pathArg;
    
    public ValidateCPBCommand() {
        super("validatecpb", "server.commands.validatecpb.desc");
        this.pathArg = this.withOptionalArg("path", "server.commands.validatecpb.path.desc", ArgTypes.STRING);
    }
    
    @Nonnull
    @Override
    protected CompletableFuture<Void> executeAsync(@Nonnull final CommandContext context) {
        if (this.pathArg.provided(context)) {
            final String path = this.pathArg.get(context);
            return CompletableFuture.runAsync(() -> convertPrefabs(context, PathUtil.get(path)));
        }
        return CompletableFuture.runAsync(() -> {
            for (final AssetPack pack : AssetModule.get().getAssetPacks()) {
                convertPrefabs(context, pack.getRoot());
            }
        });
    }
    
    private static void convertPrefabs(@Nonnull final CommandContext context, @Nonnull final Path assetPath) {
        final List<String> failed = new ObjectArrayList<String>();
        try {
            final Stream<Path> stream = Files.walk(assetPath, FileUtil.DEFAULT_WALK_TREE_OPTIONS_ARRAY);
            try {
                final CompletableFuture[] futures = stream.filter(path -> Files.isRegularFile(path, new LinkOption[0]) && path.toString().endsWith(".prefab.json")).map(path -> BsonUtil.readDocument(path, false).thenAccept(document -> {
                    BsonPrefabBufferDeserializer.INSTANCE.deserialize(path, document);
                    context.sendMessage(Message.translation("server.general.loadedPrefab").param("name", path.toString()));
                    return;
                }).exceptionally(throwable -> {
                    final String message = throwable.getCause().getMessage();
                    if (message != null) {
                        if (message.contains("Failed to find block ")) {
                            failed.add("Failed to load " + String.valueOf(path) + " because " + message);
                            return null;
                        }
                        else if (message.contains("Unable to load entity with model ")) {
                            failed.add("Failed to load " + String.valueOf(path) + " because " + message);
                            return null;
                        }
                    }
                    failed.add("Failed to load " + String.valueOf(path) + " because " + String.valueOf((message != null) ? message : throwable.getCause().getClass()));
                    new Exception("Failed to load " + String.valueOf(path), throwable.getCause()).printStackTrace();
                    return null;
                })).toArray(CompletableFuture[]::new);
                CompletableFuture.allOf((CompletableFuture<?>[])futures).join();
                if (stream != null) {
                    stream.close();
                }
            }
            catch (final Throwable t) {
                if (stream != null) {
                    try {
                        stream.close();
                    }
                    catch (final Throwable exception) {
                        t.addSuppressed(exception);
                    }
                }
                throw t;
            }
        }
        catch (final IOException e) {
            throw SneakyThrow.sneakyThrow(e);
        }
        if (!failed.isEmpty()) {
            context.sendMessage(Message.translation("server.commands.validatecpb.failed").param("failed", failed.toString()));
        }
        context.sendMessage(Message.translation("server.commands.prefabConvertionDone").param("path", assetPath.toString()));
    }
}
