package net.minecraft.server.packs.linkfs;

import com.google.common.base.Splitter;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.WatchService;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.nio.file.spi.FileSystemProvider;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;

public class LinkFileSystem extends FileSystem {
   private static final Set<String> VIEWS = Set.of("basic");
   public static final String PATH_SEPARATOR = "/";
   private static final Splitter PATH_SPLITTER = Splitter.on('/');
   private final FileStore store;
   private final FileSystemProvider provider = new LinkFSProvider();
   private final LinkFSPath root;

   LinkFileSystem(String p_251238_, LinkFileSystem.DirectoryEntry p_248738_) {
      this.store = new LinkFSFileStore(p_251238_);
      this.root = buildPath(p_248738_, this, "", (LinkFSPath)null);
   }

   private static LinkFSPath buildPath(LinkFileSystem.DirectoryEntry p_250914_, LinkFileSystem p_248904_, String p_248935_, @Nullable LinkFSPath p_250296_) {
      Object2ObjectOpenHashMap<String, LinkFSPath> object2objectopenhashmap = new Object2ObjectOpenHashMap<>();
      LinkFSPath linkfspath = new LinkFSPath(p_248904_, p_248935_, p_250296_, new PathContents.DirectoryContents(object2objectopenhashmap));
      p_250914_.files.forEach((p_249491_, p_250850_) -> {
         object2objectopenhashmap.put(p_249491_, new LinkFSPath(p_248904_, p_249491_, linkfspath, new PathContents.FileContents(p_250850_)));
      });
      p_250914_.children.forEach((p_251592_, p_251728_) -> {
         object2objectopenhashmap.put(p_251592_, buildPath(p_251728_, p_248904_, p_251592_, linkfspath));
      });
      object2objectopenhashmap.trim();
      return linkfspath;
   }

   public FileSystemProvider provider() {
      return this.provider;
   }

   public void close() {
   }

   public boolean isOpen() {
      return true;
   }

   public boolean isReadOnly() {
      return true;
   }

   public String getSeparator() {
      return "/";
   }

   public Iterable<Path> getRootDirectories() {
      return List.of(this.root);
   }

   public Iterable<FileStore> getFileStores() {
      return List.of(this.store);
   }

   public Set<String> supportedFileAttributeViews() {
      return VIEWS;
   }

   public Path getPath(String p_250018_, String... p_252159_) {
      Stream<String> stream = Stream.of(p_250018_);
      if (p_252159_.length > 0) {
         stream = Stream.concat(stream, Stream.of(p_252159_));
      }

      String s = stream.collect(Collectors.joining("/"));
      if (s.equals("/")) {
         return this.root;
      } else if (s.startsWith("/")) {
         LinkFSPath linkfspath1 = this.root;

         for(String s2 : PATH_SPLITTER.split(s.substring(1))) {
            if (s2.isEmpty()) {
               throw new IllegalArgumentException("Empty paths not allowed");
            }

            linkfspath1 = linkfspath1.resolveName(s2);
         }

         return linkfspath1;
      } else {
         LinkFSPath linkfspath = null;

         for(String s1 : PATH_SPLITTER.split(s)) {
            if (s1.isEmpty()) {
               throw new IllegalArgumentException("Empty paths not allowed");
            }

            linkfspath = new LinkFSPath(this, s1, linkfspath, PathContents.RELATIVE);
         }

         if (linkfspath == null) {
            throw new IllegalArgumentException("Empty paths not allowed");
         } else {
            return linkfspath;
         }
      }
   }

   public PathMatcher getPathMatcher(String p_250757_) {
      throw new UnsupportedOperationException();
   }

   public UserPrincipalLookupService getUserPrincipalLookupService() {
      throw new UnsupportedOperationException();
   }

   public WatchService newWatchService() {
      throw new UnsupportedOperationException();
   }

   public FileStore store() {
      return this.store;
   }

   public LinkFSPath rootPath() {
      return this.root;
   }

   public static LinkFileSystem.Builder builder() {
      return new LinkFileSystem.Builder();
   }

   public static class Builder {
      private final LinkFileSystem.DirectoryEntry root = new LinkFileSystem.DirectoryEntry();

      public LinkFileSystem.Builder put(List<String> p_249758_, String p_251234_, Path p_248766_) {
         LinkFileSystem.DirectoryEntry linkfilesystem$directoryentry = this.root;

         for(String s : p_249758_) {
            linkfilesystem$directoryentry = linkfilesystem$directoryentry.children.computeIfAbsent(s, (p_249671_) -> {
               return new LinkFileSystem.DirectoryEntry();
            });
         }

         linkfilesystem$directoryentry.files.put(p_251234_, p_248766_);
         return this;
      }

      public LinkFileSystem.Builder put(List<String> p_250158_, Path p_250483_) {
         if (p_250158_.isEmpty()) {
            throw new IllegalArgumentException("Path can't be empty");
         } else {
            int i = p_250158_.size() - 1;
            return this.put(p_250158_.subList(0, i), p_250158_.get(i), p_250483_);
         }
      }

      public FileSystem build(String p_251975_) {
         return new LinkFileSystem(p_251975_, this.root);
      }
   }

   static record DirectoryEntry(Map<String, LinkFileSystem.DirectoryEntry> children, Map<String, Path> files) {
      public DirectoryEntry() {
         this(new HashMap<>(), new HashMap<>());
      }
   }
}