package p.studio.compiler.models;

import p.studio.compiler.exceptions.BuildException;
import p.studio.compiler.messages.DependencyConfig;
import p.studio.compiler.source.identifiers.ProjectId;
import p.studio.compiler.source.tables.ProjectTable;
import p.studio.utilities.structures.ReadOnlyList;

import java.nio.file.Path;
import java.util.*;

public final class DependencyContext {
    public final DependencyConfig config;
    public final Deque<Path> pending = new ArrayDeque<>();

    public final ProjectInfoTable projectInfoTable = new ProjectInfoTable();
    public final ProjectTable projectTable = new ProjectTable();

    public final Map<String, Set<String>> projectNameAndVersions = new HashMap<>();
    public final List<ProjectId> projectIds = new ArrayList<>();
    public final List<List<ProjectId>> dependenciesByProject = new ArrayList<>();

    public Path mainProjectRootPathCanon;
    public FrontendSpec frontendSpec;
    public Integer rootStdlib;
    public ProjectId rootProjectId;
    public BuildStack stack;

    private DependencyContext(DependencyConfig config) {
        this.config = config;
    }

    public static DependencyContext basedOn(final DependencyConfig config) {
        return new DependencyContext(config);
    }

    private ReadOnlyList<ReadOnlyList<ProjectId>> buildDependenciesByProject() {
        return ReadOnlyList.wrap(this
                .dependenciesByProject
                .stream()
                .map(ReadOnlyList::wrap)
                .toList());
    }

    public ResolvedWorkspace toResolvedWorkspace() {
        if (rootProjectId == null) {
            throw new BuildException("dependenciesByProjectId: internal error: rootProjectId ProjectId not set");
        }
        if (rootStdlib == null) {
            throw new BuildException("dependenciesByProjectId: internal error: rootStdlib not set");
        }
        final var dependenciesByProject = buildDependenciesByProject();
        final var workspaceGraph = new WorkspaceGraph(projectTable, dependenciesByProject);
        return new ResolvedWorkspace(rootProjectId, frontendSpec, rootStdlib, workspaceGraph, stack);
    }


}
