package p.studio.compiler.workspaces.phases;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import p.studio.compiler.messages.DependencyConfig;
import p.studio.compiler.models.DependencyContext;
import p.studio.compiler.models.ProjectDescriptor;
import p.studio.compiler.models.ProjectInfo;
import p.studio.compiler.models.PrometeuManifest;
import p.studio.utilities.structures.ReadOnlyList;

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

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

class ValidatePhaseTest {

    @TempDir
    Path tempDir;

    @Test
    void rejectsDependencyWithHigherStdlibThanRoot() {
        final var ctx = DependencyContext.basedOn(new DependencyConfig(false, tempDir));
        final var rootPath = tempDir.resolve("root");
        final var depPath = tempDir.resolve("dep");

        final var rootProjectId = ctx.projectTable.register(ProjectDescriptor.builder()
                .rootPath(rootPath)
                .name("root")
                .version("1.0.0")
                .sourceRoots(ReadOnlyList.wrap(List.of()))
                .build());
        ctx.projectTable.register(ProjectDescriptor.builder()
                .rootPath(depPath)
                .name("dep")
                .version("1.0.0")
                .sourceRoots(ReadOnlyList.wrap(List.of()))
                .build());

        ctx.projectInfoTable.register(ProjectInfo.builder()
                .rootDirectory(rootPath)
                .manifestPath(rootPath.resolve("prometeu.json"))
                .manifest(new PrometeuManifest("root", "1.0.0", "pbs", 1, ReadOnlyList.wrap(List.of())))
                .build());
        ctx.projectInfoTable.register(ProjectInfo.builder()
                .rootDirectory(depPath)
                .manifestPath(depPath.resolve("prometeu.json"))
                .manifest(new PrometeuManifest("dep", "1.0.0", "pbs", 2, ReadOnlyList.wrap(List.of())))
                .build());

        ctx.rootProjectId = rootProjectId;
        ctx.rootStdlib = 1;
        ctx.dependenciesByProject.add(List.of());
        ctx.dependenciesByProject.add(List.of());
        ctx.projectNameAndVersions.put("root", new java.util.HashSet<>(List.of("1.0.0")));
        ctx.projectNameAndVersions.put("dep", new java.util.HashSet<>(List.of("1.0.0")));

        final var issues = new ValidatePhase().run(ctx);

        assertTrue(issues.hasErrors());
        assertTrue(issues.asCollection().stream().anyMatch(issue -> issue.getMessage().contains("incompatible stdlib")));
    }

    @Test
    void acceptsDependencyWithLowerOrEqualStdlibThanRoot() {
        final var ctx = DependencyContext.basedOn(new DependencyConfig(false, tempDir));
        final var rootPath = tempDir.resolve("root");
        final var depPath = tempDir.resolve("dep");

        final var rootProjectId = ctx.projectTable.register(ProjectDescriptor.builder()
                .rootPath(rootPath)
                .name("root")
                .version("1.0.0")
                .sourceRoots(ReadOnlyList.wrap(List.of()))
                .build());
        ctx.projectTable.register(ProjectDescriptor.builder()
                .rootPath(depPath)
                .name("dep")
                .version("1.0.0")
                .sourceRoots(ReadOnlyList.wrap(List.of()))
                .build());

        ctx.projectInfoTable.register(ProjectInfo.builder()
                .rootDirectory(rootPath)
                .manifestPath(rootPath.resolve("prometeu.json"))
                .manifest(new PrometeuManifest("root", "1.0.0", "pbs", 2, ReadOnlyList.wrap(List.of())))
                .build());
        ctx.projectInfoTable.register(ProjectInfo.builder()
                .rootDirectory(depPath)
                .manifestPath(depPath.resolve("prometeu.json"))
                .manifest(new PrometeuManifest("dep", "1.0.0", "pbs", 1, ReadOnlyList.wrap(List.of())))
                .build());

        ctx.rootProjectId = rootProjectId;
        ctx.rootStdlib = 2;
        ctx.dependenciesByProject.add(List.of());
        ctx.dependenciesByProject.add(List.of());
        ctx.projectNameAndVersions.put("root", new java.util.HashSet<>(List.of("1.0.0")));
        ctx.projectNameAndVersions.put("dep", new java.util.HashSet<>(List.of("1.0.0")));

        final var issues = new ValidatePhase().run(ctx);

        assertFalse(issues.hasErrors());
    }
}
