package p.studio.compiler.pbs.stdlib;

import p.studio.utilities.structures.ReadOnlyList;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

public final class ResourceStdlibEnvironmentResolver implements StdlibEnvironmentResolver {
    private static final String STDLIB_ROOT = "stdlib";

    @Override
    public StdlibEnvironment resolve(final int stdlibVersion) {
        return new ResourceStdlibEnvironment(stdlibVersion);
    }

    private static final class ResourceStdlibEnvironment implements StdlibEnvironment {
        private final int stdlibVersion;

        private ResourceStdlibEnvironment(final int stdlibVersion) {
            this.stdlibVersion = stdlibVersion;
        }

        @Override
        public Optional<StdlibModuleSource> resolveModule(
                final String project,
                final ReadOnlyList<String> pathSegments) {
            final var moduleBasePath = moduleBasePath(project, pathSegments);
            final var mainSource = readResource(moduleBasePath + "/main.pbs");
            final var barrelSource = readResource(moduleBasePath + "/mod.barrel");
            if (mainSource.isEmpty() || barrelSource.isEmpty()) {
                return Optional.empty();
            }

            return Optional.of(new StdlibModuleSource(
                    project,
                    pathSegments,
                    ReadOnlyList.wrap(java.util.List.of(new StdlibModuleSource.SourceFile("main.pbs", mainSource.get()))),
                    barrelSource.get()));
        }

        private String moduleBasePath(
                final String project,
                final ReadOnlyList<String> pathSegments) {
            final var pathBuilder = new StringBuilder();
            pathBuilder.append(STDLIB_ROOT)
                    .append('/')
                    .append(stdlibVersion)
                    .append('/')
                    .append(project);
            for (final var pathSegment : pathSegments) {
                pathBuilder.append('/').append(pathSegment);
            }
            return pathBuilder.toString();
        }

        private Optional<String> readResource(final String resourcePath) {
            final var classLoader = ResourceStdlibEnvironmentResolver.class.getClassLoader();
            if (classLoader == null) {
                return Optional.empty();
            }

            try (InputStream stream = classLoader.getResourceAsStream(resourcePath)) {
                if (stream == null) {
                    return Optional.empty();
                }
                return Optional.of(new String(stream.readAllBytes(), StandardCharsets.UTF_8));
            } catch (IOException ignored) {
                return Optional.empty();
            }
        }
    }
}
