package net.minecraft.server.packs;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.mojang.logging.LogUtils;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import net.minecraft.Util;
import net.minecraft.util.FileSystemUtil;
import org.slf4j.Logger;

public class VanillaPackResourcesBuilder {
    private static final Logger LOGGER = LogUtils.getLogger();
    public static Consumer<VanillaPackResourcesBuilder> developmentConfig = builder -> {};
    private static final Map<PackType, Path> ROOT_DIR_BY_TYPE = Util.make(() -> {
        synchronized (VanillaPackResources.class) {
            Builder<PackType, Path> builder = ImmutableMap.builder();

            for (PackType packType : PackType.values()) {
                String string = "/" + packType.getDirectory() + "/.mcassetsroot";
                URL resource = VanillaPackResources.class.getResource(string);
                if (resource == null) {
                    LOGGER.error("File {} does not exist in classpath", string);
                } else {
                    try {
                        URI uri = resource.toURI();
                        String scheme = uri.getScheme();
                        if (!"jar".equals(scheme) && !"file".equals(scheme)) {
                            LOGGER.warn("Assets URL '{}' uses unexpected schema", uri);
                        }

                        Path path = FileSystemUtil.safeGetPath(uri);
                        builder.put(packType, path.getParent());
                    } catch (Exception var12) {
                        LOGGER.error("Couldn't resolve path to vanilla assets", (Throwable)var12);
                    }
                }
            }

            return builder.build();
        }
    });
    private final Set<Path> rootPaths = new LinkedHashSet<>();
    private final Map<PackType, Set<Path>> pathsForType = new EnumMap<>(PackType.class);
    private BuiltInMetadata metadata = BuiltInMetadata.of();
    private final Set<String> namespaces = new HashSet<>();

    private boolean validateDirPath(Path path) {
        if (!Files.exists(path)) {
            return false;
        } else if (!Files.isDirectory(path)) {
            throw new IllegalArgumentException("Path " + path.toAbsolutePath() + " is not directory");
        } else {
            return true;
        }
    }

    private void pushRootPath(Path rootPath) {
        if (this.validateDirPath(rootPath)) {
            this.rootPaths.add(rootPath);
        }
    }

    private void pushPathForType(PackType packType, Path path) {
        if (this.validateDirPath(path)) {
            this.pathsForType.computeIfAbsent(packType, type -> new LinkedHashSet<>()).add(path);
        }
    }

    public VanillaPackResourcesBuilder pushJarResources() {
        ROOT_DIR_BY_TYPE.forEach((packType, path) -> {
            this.pushRootPath(path.getParent());
            this.pushPathForType(packType, path);
        });
        return this;
    }

    public VanillaPackResourcesBuilder pushClasspathResources(PackType packType, Class<?> clazz) {
        Enumeration<URL> enumeration = null;

        try {
            enumeration = clazz.getClassLoader().getResources(packType.getDirectory() + "/");
        } catch (IOException var8) {
        }

        while (enumeration != null && enumeration.hasMoreElements()) {
            URL url = enumeration.nextElement();

            try {
                URI uri = url.toURI();
                if ("file".equals(uri.getScheme())) {
                    Path path = Paths.get(uri);
                    this.pushRootPath(path.getParent());
                    this.pushPathForType(packType, path);
                }
            } catch (Exception var7) {
                LOGGER.error("Failed to extract path from {}", url, var7);
            }
        }

        return this;
    }

    public VanillaPackResourcesBuilder applyDevelopmentConfig() {
        developmentConfig.accept(this);
        return this;
    }

    public VanillaPackResourcesBuilder pushUniversalPath(Path path) {
        this.pushRootPath(path);

        for (PackType packType : PackType.values()) {
            this.pushPathForType(packType, path.resolve(packType.getDirectory()));
        }

        return this;
    }

    public VanillaPackResourcesBuilder pushAssetPath(PackType packType, Path path) {
        this.pushRootPath(path);
        this.pushPathForType(packType, path);
        return this;
    }

    public VanillaPackResourcesBuilder setMetadata(BuiltInMetadata metadata) {
        this.metadata = metadata;
        return this;
    }

    public VanillaPackResourcesBuilder exposeNamespace(String... namespaces) {
        this.namespaces.addAll(Arrays.asList(namespaces));
        return this;
    }

    public VanillaPackResources build(PackLocationInfo location) {
        return new VanillaPackResources(
            location,
            this.metadata,
            Set.copyOf(this.namespaces),
            copyAndReverse(this.rootPaths),
            Util.makeEnumMap(PackType.class, packType -> copyAndReverse(this.pathsForType.getOrDefault(packType, Set.of())))
        );
    }

    private static List<Path> copyAndReverse(Collection<Path> paths) {
        List<Path> list = new ArrayList<>(paths);
        Collections.reverse(list);
        return List.copyOf(list);
    }
}
