package p.studio.compiler.services;

import p.studio.compiler.models.IRGlobalVisibility;
import p.studio.compiler.source.identifiers.ModuleId;
import p.studio.compiler.source.tables.ModuleReference;
import p.studio.compiler.source.tables.ModuleTable;
import p.studio.utilities.structures.ReadOnlyList;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

record PbsModuleAssembly(
        ReadOnlyList<PbsParsedSourceFile> parsedSourceFiles,
        Map<ModuleId, Set<ModuleId>> moduleDependencyGraph,
        ReadOnlyList<ModuleReference> canonicalModulePool,
        Set<ModuleId> failedModuleIds,
        ModuleTable moduleTable,
        Map<ModuleId, Map<String, IRGlobalVisibility>> globalVisibilityByModule) {
    PbsModuleAssembly {
        parsedSourceFiles = parsedSourceFiles == null ? ReadOnlyList.empty() : parsedSourceFiles;
        canonicalModulePool = canonicalModulePool == null ? ReadOnlyList.empty() : canonicalModulePool;
        failedModuleIds = failedModuleIds == null ? Set.of() : Set.copyOf(failedModuleIds);

        if (moduleDependencyGraph == null || moduleDependencyGraph.isEmpty()) {
            moduleDependencyGraph = Map.of();
        } else {
            final var copiedGraph = new HashMap<ModuleId, Set<ModuleId>>();
            for (final var entry : moduleDependencyGraph.entrySet()) {
                copiedGraph.put(entry.getKey(), Set.copyOf(entry.getValue() == null ? Set.of() : entry.getValue()));
            }
            moduleDependencyGraph = Map.copyOf(copiedGraph);
        }

        if (moduleTable == null) {
            moduleTable = new ModuleTable();
        }
        if (globalVisibilityByModule == null || globalVisibilityByModule.isEmpty()) {
            globalVisibilityByModule = Map.of();
        } else {
            final var copiedVisibility = new HashMap<ModuleId, Map<String, IRGlobalVisibility>>();
            for (final var entry : globalVisibilityByModule.entrySet()) {
                copiedVisibility.put(entry.getKey(), Map.copyOf(entry.getValue() == null ? Map.of() : entry.getValue()));
            }
            globalVisibilityByModule = Map.copyOf(copiedVisibility);
        }
    }

    Set<ModuleId> mutableFailedModuleIds() {
        return new HashSet<>(failedModuleIds);
    }
}
