import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
 
import java.util.List;
import java.util.NoSuchElementException;

public class BackendTests {

 /**
     * roleTest1 — Tests loadGraphData and getListOfAll.
     *
     * Verifies that loadGraphData parses a valid dot file without throwing,
     * and that getListOfAll returns a non-empty list after loading. Also tests
     * that calling loadGraphData a second time
     * completes without error, and that
     * getListOfAll is still non-empty afterward.
     */
    @Test
    public void roleTest1() {
        Graph_Placeholder graph = new Graph_Placeholder();
        Backend backend = new Backend(graph);
 
        // loadGraphData on a valid file should not throw
        assertDoesNotThrow(() -> backend.loadGraphData("europeanRail.dot"),
            "loadGraphData should not throw on a valid dot file");
 
        List<String> allLocations = backend.getListOfAll();
        assertNotNull(allLocations,
            "getListOfAll should never return null");
        assertFalse(allLocations.isEmpty(),
            "getListOfAll should return at least one location after loading");
 
        assertDoesNotThrow(() -> backend.loadGraphData("europeanRail.dot"),
            "A second loadGraphData call should also succeed without throwing");
 
        List<String> reloaded = backend.getListOfAll();
        assertFalse(reloaded.isEmpty(),
            "getListOfAll should still be non-empty after a reload");
    }

 /**
     * roleTest2 — Tests findLocationsOnShortestPath and findTimesOnShortestPath.
     *
     * Works directly off Graph_Placeholder's hard-coded path without calling
     * loadGraphData, so the placeholder's pre-seeded nodes are the data source.
     *
     * Also verifies that both methods return an empty list (not throw) when
     * the start node does not exist in the graph.
     */
    @Test
    public void roleTest2() {
        Graph_Placeholder graph = new Graph_Placeholder();
        Backend backend = new Backend(graph);
 
        String start = "Union South";
        String mid   = "Computer Sciences and Statistics";
        String end   = "Weeks Hall for Geological Sciences";
 
        // findLocationsOnShortestPath — normal case
        List<String> locations = backend.findLocationsOnShortestPath(start, end);
        assertNotNull(locations,
            "findLocationsOnShortestPath should never return null");
        assertEquals(3, locations.size(),
            "Path from Union South to Weeks Hall should contain 3 nodes");
        assertEquals(start, locations.get(0), "First node should be the start");
        assertEquals(mid,   locations.get(1), "Middle node should be Computer Sciences and Statistics");
        assertEquals(end,   locations.get(2), "Last node should be the end");
 
        // findTimesOnShortestPath — normal case
        List<Double> times = backend.findTimesOnShortestPath(start, end);
        assertNotNull(times,
            "findTimesOnShortestPath should never return null");
        assertEquals(2, times.size(),
            "A 3-node path should produce exactly 2 edge weights");
        assertEquals(1.0, times.get(0), 1e-9,
            "First edge weight should be 1.0 (placeholder getEdge returns index 1)");
        assertEquals(2.0, times.get(1), 1e-9,
            "Second edge weight should be 2.0 (placeholder getEdge returns index 2)");
 
        // Both methods must return empty list (not throw) for an unknown start
        List<String> noLocations = backend.findLocationsOnShortestPath("Nowhere", end);
        assertNotNull(noLocations, "Result for unknown start should not be null");
        assertTrue(noLocations.isEmpty(),
            "findLocationsOnShortestPath should return empty list when no path exists");
 
        List<Double> noTimes = backend.findTimesOnShortestPath("Nowhere", end);
        assertNotNull(noTimes, "Times for unknown start should not be null");
        assertTrue(noTimes.isEmpty(),
            "findTimesOnShortestPath should return empty list when no path exists");
    }
/**
     * roleTest3 — Tests getTenClosestLocations and getListOfAll.
     *
     * First confirms getListOfAll returns an empty list on a fresh backend
     * (before loadGraphData has been called), since nodeList starts empty.
     *
     * Then calls loadGraphData with the real dot file to populate nodeList so
     * that getTenClosestLocations has candidates to iterate over. Even though
     * Graph_Placeholder only truly stores its three pre-seeded nodes, those
     * nodes are present in nodeList after the load, and containsNode /
     * shortestPathCost on the placeholder operate correctly for them.
     *
     * Also verifies that NoSuchElementException is thrown for an unknown start.
     */
    @Test
    public void roleTest3() {
Graph_Placeholder graph = new Graph_Placeholder();
        Backend backend = new Backend(graph);
 
        // getListOfAll before any load must return empty list, not null
        List<String> beforeLoad = backend.getListOfAll();
        assertNotNull(beforeLoad,
            "getListOfAll before loading should return an empty list, not null");
        assertTrue(beforeLoad.isEmpty(),
            "getListOfAll should be empty before loadGraphData is called");
 
        // Load the dot file so nodeList is populated
        try {
            backend.loadGraphData("europeanRail.dot");
        } catch (Exception e) {
            fail("loadGraphData should not throw on a valid dot file, but threw: " + e.getMessage());
        }
 
        List<String> afterLoad = backend.getListOfAll();
        assertFalse(afterLoad.isEmpty(),
            "getListOfAll should be non-empty after loadGraphData");
 
        // getTenClosestLocations — structural contracts only.
        // "Union South" is one of Graph_Placeholder's pre-seeded nodes so
        // containsNode returns true and the call should succeed.
        List<String> closest = backend.getTenClosestLocations("Union South");
        assertNotNull(closest,
            "getTenClosestLocations should never return null");
        assertFalse(closest.isEmpty(),
            "There should be at least one location reachable from Union South");
        assertTrue(closest.size() <= 10,
            "getTenClosestLocations should return at most 10 results");
 
 
        // Must throw for a node not in the graph
        try {
            backend.getTenClosestLocations("Nonexistent City");
            fail("getTenClosestLocations should have thrown NoSuchElementException for unknown start");
        } catch (NoSuchElementException e) {
            // expected — test passes
        }
    }
}
