package land.chipmunk.chipmunkmod.command.arguments;

import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import net.minecraft.network.chat.Component;

public class LocationArgumentType implements ArgumentType<Object> {
    private static final Collection<String> EXAMPLES = Arrays.asList("songs/amogus.mid", "images/cat.jpg", "videos/badapple.mp4");

    private final boolean allowsUrls;
    private final boolean allowsPaths;
    private final Path root;

    private LocationArgumentType (final boolean allowsUrls, final boolean allowsPaths, final Path root) {
        this.allowsUrls = allowsUrls;
        this.allowsPaths = allowsPaths;
        this.root = root.toAbsolutePath().normalize();
    }

    public static LocationArgumentType location (final Path rootPath) { return new LocationArgumentType(true, true, rootPath); }

    public static LocationArgumentType url () { return new LocationArgumentType(true, false, null); }

    public static LocationArgumentType filepath (final Path rootPath) { return new LocationArgumentType(false, true, rootPath); }

    private static Object getLocation (final CommandContext<?> context, final String name) {
        return context.getArgument(name, Object.class);
    }

    public static URL getUrl (final CommandContext<?> context, final String name) {
        final Object location = getLocation(context, name);
        if (location instanceof URL) return (URL) location;
        try {
            if (location instanceof Path) return new URI("file", "", "", -1, location.toString(), "", "").toURL();
        } catch (final MalformedURLException | URISyntaxException ignored) {
            return null; // The real question is whether this will actually ever get called
        }
        return null;
    }

    public static Path getPath (final CommandContext<?> context, final String name) {
        final Object location = getLocation(context, name);
        if (location instanceof Path) return (Path) location;
        return null;
    }

    @Override
    public Object parse (final StringReader reader) throws CommandSyntaxException {
        final String remaining = reader.getString().substring(reader.getCursor());
        if (allowsUrls && isUrlStart(remaining)) return parseUrl(reader);
        if (allowsPaths) return parsePath(reader);
        return null;
    }

    public boolean isUrlStart (final String string) { return string.startsWith("http://") || string.startsWith("https://") || string.startsWith("ftp://"); }

    public URL parseUrl (final StringReader reader) throws CommandSyntaxException {
        final StringBuilder sb = new StringBuilder();
        while (reader.canRead() && reader.peek() != ' ') {
            sb.append(reader.read());
        }

        try {
            return new URI(sb.toString()).toURL();
        } catch (final MalformedURLException | URISyntaxException exception) {
            throw new SimpleCommandExceptionType(Component.literal(exception.getMessage())).create();
        }
    }

    public Path parsePath (final StringReader reader) throws CommandSyntaxException {
        final String pathString = reader.readString();
        return Path.of(root.toString(), pathString).toAbsolutePath().normalize();
    }

    @Override
    public Collection<String> getExamples () { return EXAMPLES; }
}
