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

package com.hypixel.hytale.builtin.buildertools.prefablist;

import javax.annotation.Nullable;
import java.nio.file.FileVisitor;
import com.hypixel.hytale.common.util.StringCompareUtil;
import java.util.Locale;
import java.nio.file.FileVisitResult;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.SimpleFileVisitor;
import java.util.Comparator;
import java.nio.file.DirectoryStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.util.Iterator;
import com.hypixel.hytale.server.core.prefab.PrefabStore;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import java.nio.file.Path;
import com.hypixel.hytale.server.core.ui.browser.FileListProvider;

public class AssetPrefabFileProvider implements FileListProvider
{
    private static final String PREFAB_EXTENSION = ".prefab.json";
    private static final int MAX_SEARCH_RESULTS = 50;
    private static final String BASE_ASSET_PACK_DISPLAY_NAME = "HytaleAssets";
    
    @Nonnull
    @Override
    public List<FileEntry> getFiles(@Nonnull final Path currentDir, @Nonnull final String searchQuery) {
        final String currentDirStr = currentDir.toString().replace('\\', '/');
        if (!searchQuery.isEmpty()) {
            return this.buildSearchResults(currentDirStr, searchQuery);
        }
        if (currentDirStr.isEmpty()) {
            return this.buildPackListings();
        }
        return this.buildPackDirectoryListing(currentDirStr);
    }
    
    @Nonnull
    private List<FileEntry> buildPackListings() {
        final List<FileEntry> entries = new ObjectArrayList<FileEntry>();
        for (final PrefabStore.AssetPackPrefabPath packPath : PrefabStore.get().getAllAssetPrefabPaths()) {
            final String displayName = packPath.getDisplayName();
            final String packKey = this.getPackKey(packPath);
            entries.add(new FileEntry(packKey, displayName, true));
        }
        entries.sort((a, b) -> {
            final boolean aIsBase = "HytaleAssets".equals(a.displayName());
            final boolean bIsBase = "HytaleAssets".equals(b.displayName());
            if (aIsBase != bIsBase) {
                return aIsBase ? -1 : 1;
            }
            else {
                return a.displayName().compareToIgnoreCase(b.displayName());
            }
        });
        return entries;
    }
    
    @Nonnull
    private List<FileEntry> buildPackDirectoryListing(@Nonnull final String currentDirStr) {
        final List<FileEntry> entries = new ObjectArrayList<FileEntry>();
        final String[] parts = currentDirStr.split("/", 2);
        final String packKey = parts[0];
        final String subPath = (parts.length > 1) ? parts[1] : "";
        final PrefabStore.AssetPackPrefabPath packPath = this.findPackByKey(packKey);
        if (packPath == null) {
            return entries;
        }
        Path targetPath = packPath.prefabsPath();
        if (!subPath.isEmpty()) {
            targetPath = targetPath.resolve(subPath);
        }
        if (!Files.isDirectory(targetPath, new LinkOption[0])) {
            return entries;
        }
        try (final DirectoryStream<Path> stream = Files.newDirectoryStream(targetPath)) {
            for (final Path file : stream) {
                final String fileName = file.getFileName().toString();
                if (fileName.startsWith(".")) {
                    continue;
                }
                final boolean isDirectory = Files.isDirectory(file, new LinkOption[0]);
                if (!isDirectory && !fileName.endsWith(".prefab.json")) {
                    continue;
                }
                final String displayName = isDirectory ? fileName : this.removeExtension(fileName);
                entries.add(new FileEntry(fileName, displayName, isDirectory));
            }
        }
        catch (final IOException ex) {}
        entries.sort((a, b) -> {
            if (a.isDirectory() == b.isDirectory()) {
                return a.displayName().compareToIgnoreCase(b.displayName());
            }
            else {
                return a.isDirectory() ? -1 : 1;
            }
        });
        return entries;
    }
    
    @Nonnull
    private List<FileEntry> buildSearchResults(@Nonnull final String currentDirStr, @Nonnull final String searchQuery) {
        final List<SearchResult> allResults = new ObjectArrayList<SearchResult>();
        final String lowerQuery = searchQuery.toLowerCase();
        if (currentDirStr.isEmpty()) {
            for (final PrefabStore.AssetPackPrefabPath packPath : PrefabStore.get().getAllAssetPrefabPaths()) {
                final String packKey = this.getPackKey(packPath);
                this.searchInDirectory(packPath.prefabsPath(), packKey, "", lowerQuery, allResults);
            }
        }
        else {
            final String[] parts = currentDirStr.split("/", 2);
            final String packKey2 = parts[0];
            final String subPath = (parts.length > 1) ? parts[1] : "";
            final PrefabStore.AssetPackPrefabPath packPath2 = this.findPackByKey(packKey2);
            if (packPath2 != null) {
                Path searchRoot = packPath2.prefabsPath();
                if (!subPath.isEmpty()) {
                    searchRoot = searchRoot.resolve(subPath);
                }
                this.searchInDirectory(searchRoot, packKey2, subPath, lowerQuery, allResults);
            }
        }
        allResults.sort(Comparator.comparingInt(SearchResult::score).reversed());
        final List<FileEntry> entries = new ObjectArrayList<FileEntry>();
        for (int i = 0; i < Math.min(allResults.size(), 50); ++i) {
            final SearchResult result = allResults.get(i);
            entries.add(new FileEntry(result.relativePath(), result.displayName(), false, false, result.score()));
        }
        return entries;
    }
    
    private void searchInDirectory(@Nonnull final Path root, @Nonnull final String packKey, @Nonnull final String basePath, @Nonnull final String searchQuery, @Nonnull final List<SearchResult> results) {
        if (!Files.isDirectory(root, new LinkOption[0])) {
            return;
        }
        try {
            Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
                @Nonnull
                @Override
                public FileVisitResult visitFile(@Nonnull final Path file, @Nonnull final BasicFileAttributes attrs) {
                    final String fileName = file.getFileName().toString();
                    if (fileName.endsWith(".prefab.json")) {
                        final String baseName = AssetPrefabFileProvider.this.removeExtension(fileName);
                        final int score = StringCompareUtil.getFuzzyDistance(baseName.toLowerCase(), searchQuery, Locale.ENGLISH);
                        if (score > 0) {
                            final Path relativePath = root.relativize(file);
                            final String fullRelativePath = basePath.isEmpty() ? (packKey + "/" + relativePath.toString().replace('\\', '/')) : (packKey + "/" + basePath + "/" + relativePath.toString().replace('\\', '/'));
                            results.add(new SearchResult(fullRelativePath, baseName, score));
                        }
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
        }
        catch (final IOException ex) {}
    }
    
    @Nonnull
    private String getPackKey(@Nonnull final PrefabStore.AssetPackPrefabPath packPath) {
        return packPath.getDisplayName();
    }
    
    @Nullable
    private PrefabStore.AssetPackPrefabPath findPackByKey(@Nonnull final String packKey) {
        for (final PrefabStore.AssetPackPrefabPath packPath : PrefabStore.get().getAllAssetPrefabPaths()) {
            if (this.getPackKey(packPath).equals(packKey)) {
                return packPath;
            }
        }
        return null;
    }
    
    @Nonnull
    private String removeExtension(@Nonnull final String fileName) {
        if (fileName.endsWith(".prefab.json")) {
            return fileName.substring(0, fileName.length() - ".prefab.json".length());
        }
        return fileName;
    }
    
    @Nullable
    public Path resolveVirtualPath(@Nonnull final String virtualPath) {
        if (virtualPath.isEmpty()) {
            return null;
        }
        final String[] parts = virtualPath.split("/", 2);
        final String packKey = parts[0];
        final String subPath = (parts.length > 1) ? parts[1] : "";
        final PrefabStore.AssetPackPrefabPath packPath = this.findPackByKey(packKey);
        if (packPath == null) {
            return null;
        }
        if (subPath.isEmpty()) {
            return packPath.prefabsPath();
        }
        return packPath.prefabsPath().resolve(subPath);
    }
    
    @Nonnull
    public String getPackDisplayName(@Nonnull final String packKey) {
        final PrefabStore.AssetPackPrefabPath packPath = this.findPackByKey(packKey);
        return (packPath != null) ? packPath.getDisplayName() : packKey;
    }
    
    record SearchResult(@Nonnull String relativePath, @Nonnull String displayName, int score) {
        @Nonnull
        public String relativePath() {
            return this.relativePath;
        }
        
        @Nonnull
        public String displayName() {
            return this.displayName;
        }
    }
}
