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

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

import com.hypixel.hytale.server.core.command.system.arguments.system.Argument;
import java.util.Collections;
import java.io.IOException;
import java.nio.file.Path;
import com.hypixel.hytale.server.core.asset.common.CommonAsset;
import com.hypixel.hytale.sneakythrow.SneakyThrow;
import java.nio.file.Files;
import com.hypixel.hytale.server.core.asset.common.asset.FileCommonAsset;
import java.util.Iterator;
import java.util.Collection;
import com.hypixel.hytale.server.core.util.message.MessageFormat;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Set;
import com.hypixel.hytale.common.util.FormatUtil;
import com.hypixel.hytale.server.core.Message;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import com.hypixel.hytale.server.core.asset.common.CommonAssetRegistry;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.concurrent.CompletableFuture;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.command.system.arguments.system.FlagArg;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractAsyncCommand;

public class AssetsDuplicatesCommand extends AbstractAsyncCommand
{
    @Nonnull
    private final FlagArg reverseFlag;
    
    public AssetsDuplicatesCommand() {
        super("duplicates", "server.commands.assets.duplicates.desc");
        this.reverseFlag = this.withFlagArg("reverse", "server.commands.assets.duplicates.reverse.desc");
    }
    
    @Nonnull
    @Override
    protected CompletableFuture<Void> executeAsync(@Nonnull final CommandContext context) {
        final boolean reverse = ((Argument<Arg, Boolean>)this.reverseFlag).get(context);
        final List<CompletableFuture<Void>> futures = new ObjectArrayList<CompletableFuture<Void>>();
        final List<DuplicatedAssetInfo> duplicates = new ObjectArrayList<DuplicatedAssetInfo>();
        for (final Map.Entry<String, List<CommonAssetRegistry.PackAsset>> entry : CommonAssetRegistry.getDuplicatedAssets().entrySet()) {
            final DuplicatedAssetInfo duplicateInfo = new DuplicatedAssetInfo(entry.getKey(), entry.getValue());
            duplicates.add(duplicateInfo);
            futures.add(duplicateInfo.calculateTotalSize());
        }
        return CompletableFuture.allOf((CompletableFuture<?>[])futures.toArray(CompletableFuture[]::new)).thenAccept(aVoid -> {
            duplicates.sort(reverse ? DuplicatedAssetInfo.COMPARATOR_REVERSE : DuplicatedAssetInfo.COMPARATOR);
            long totalWastedSpace = 0L;
            for (final DuplicatedAssetInfo duplicateInfo2 : duplicates) {
                final Message header = Message.translation("server.commands.assets.duplicates.header").param("hash", duplicateInfo2.hash).param("wastedBytes", FormatUtil.bytesToString(duplicateInfo2.wastedSpace));
                final Set<Message> duplicateAssets = duplicateInfo2.assets.stream().map(a -> a.pack() + ":" + a.asset().getName()).map((Function<? super Object, ?>)Message::raw).collect((Collector<? super Object, ?, Set<Message>>)Collectors.toSet());
                context.sendMessage(MessageFormat.list(header, duplicateAssets));
                totalWastedSpace += duplicateInfo2.wastedSpace;
            }
            context.sendMessage(Message.translation("server.commands.assets.duplicates.total").param("wastedBytes", FormatUtil.bytesToString(totalWastedSpace)));
        });
    }
    
    public static class DuplicatedAssetInfo
    {
        @Nonnull
        public static final Comparator<DuplicatedAssetInfo> COMPARATOR;
        @Nonnull
        public static final Comparator<DuplicatedAssetInfo> COMPARATOR_REVERSE;
        @Nonnull
        final String hash;
        @Nonnull
        final List<CommonAssetRegistry.PackAsset> assets;
        long wastedSpace;
        
        public DuplicatedAssetInfo(@Nonnull final String hash, @Nonnull final List<CommonAssetRegistry.PackAsset> assets) {
            this.hash = hash;
            this.assets = assets;
        }
        
        @Nonnull
        public CompletableFuture<Void> calculateTotalSize() {
            final CommonAsset commonAsset = this.assets.getFirst().asset();
            if (commonAsset instanceof final FileCommonAsset fileCommonAsset) {
                final Path path = fileCommonAsset.getFile();
                return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> this.wastedSpace = Files.size(path) * (this.assets.size() - 1)));
            }
            return commonAsset.getBlob().thenAccept(bytes -> this.wastedSpace = bytes.length * (long)(this.assets.size() - 1));
        }
        
        static {
            COMPARATOR = Comparator.comparingLong(o -> o.wastedSpace);
            COMPARATOR_REVERSE = Collections.reverseOrder(DuplicatedAssetInfo.COMPARATOR);
        }
    }
}
