package p.studio.utilities.structures;

import org.junit.jupiter.api.Test;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;

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

class DependencyGraphAnaliserTest {

    @Test
    void shouldTopologicallyOrderSimpleDag() {
        final var graph = new LinkedHashMap<String, Set<String>>();
        graph.put("app", Set.of("core", "util"));
        graph.put("core", Set.of("util"));
        graph.put("util", Set.of());

        final var analysis = new DependencyGraphAnaliser<>(String::compareTo).analyse(graph);

        assertTrue(analysis.acyclic());
        assertEquals(ReadOnlyList.wrap(List.of("util", "core", "app")), analysis.traversalOrder());
        assertTrue(analysis.cycleComponents().isEmpty());
    }

    @Test
    void shouldDetectCycle() {
        final var graph = new LinkedHashMap<String, Set<String>>();
        graph.put("a", Set.of("b"));
        graph.put("b", Set.of("c"));
        graph.put("c", Set.of("a"));

        final var analysis = new DependencyGraphAnaliser<>(String::compareTo).analyse(graph);

        assertFalse(analysis.acyclic());
        assertEquals(1, analysis.cycleComponents().size());
        assertEquals(ReadOnlyList.wrap(List.of("a", "b", "c")), analysis.cycleComponents().getFirst());
    }

    @Test
    void shouldProduceDeterministicOrderForDisconnectedGraph() {
        final var graph = new LinkedHashMap<String, Set<String>>();
        graph.put("zeta", Set.of());
        graph.put("alpha", Set.of());
        graph.put("beta", Set.of("alpha"));

        final var analysis = new DependencyGraphAnaliser<>(String::compareTo).analyse(graph);

        assertTrue(analysis.acyclic());
        assertEquals(ReadOnlyList.wrap(List.of("alpha", "beta", "zeta")), analysis.traversalOrder());
    }

    @Test
    void shouldTreatSelfLoopAsCycle() {
        final var graph = new LinkedHashMap<String, Set<String>>();
        graph.put("self", Set.of("self"));

        final var analysis = new DependencyGraphAnaliser<>(String::compareTo).analyse(graph);

        assertFalse(analysis.acyclic());
        assertEquals(1, analysis.cycleComponents().size());
        assertEquals(ReadOnlyList.wrap(List.of("self")), analysis.cycleComponents().getFirst());
    }
}
