import java.util.List;
import java.util.NoSuchElementException;
/**
 * It will enable users to access the functionality exposed by the BackendInterface.
 */
public class Frontend implements FrontendInterface{

    private BackendInterface backend;

    /**
     * Constructor
     * @param backend is used for shortest path computations
     */
    public Frontend(BackendInterface backend) {
        this.backend = backend;
    }
    
    /**
     * Returns an HTML fragment that can be embedded within the body of a
     * larger html page.  This HTML output should include:
     * - a text input field with the id="start", for the start location
     * - a text input field with the id="end", for the destination
     * - a button labelled "Find Shortest Path" to request this computation
     * Ensure that these text fields are clearly labelled, so that the user
     * can understand how to use them.
     * @return an HTML string that contains input controls that the user can
     *         make use of to request a shortest path computation
     */
    @Override
    public String generateShortestPathPromptHTML() {
        //Block of String that contains the HTML for the text inputs and button input as well as the label for the text inputs
        return """
        <label for="start">Start Location:</label>
        <input type="text" id="start"></input>
        <label for="end">End Location:</label>
        <input type="text" id="end"></input>
        <input type="button" value="Find Shortest Path"></input>
                """;
    }
    
    /**
     * Returns an HTML fragment that can be embedded within the body of a
     * larger html page.  This HTML output should include:
     * - a paragraph (p) that describes the path's start and end locations
     * - an ordered list (ol) of locations along that shortest path
     * - a paragraph (p) that includes the total travel time along this path
     * Or if there is no such path, the HTML returned should instead indicate 
     * the kind of problem encountered.
     * @param start is the starting location to find a shortest path from
     * @param end is the destination that this shortest path should end at
     * @return an HTML string that describes the shortest path between these
     *         two locations
     */
    @Override
    public String generateShortestPathResponseHTML(String start, String end) {
        //List of String to contain the backend method that returns the locations along the shortest path
        List<String> locationList = backend.findLocationsOnShortestPath(start, end);
        StringBuilder locations = new StringBuilder();
        if (locationList.isEmpty()) {//If it is empty then there is no such path
            return "<p>There is no such path or some other problem occured.</p>";
        } else {
            //Adding the locations from locationsList formatted as HTML list elements
            for (String location : locationList) {
                locations.append("<li>").append(location).append("</li>");
            }
        }

        //List of Double that contain all the times from the backend method that returns the times between 2 nodes in the path
        List<Double> times = backend.findTimesOnShortestPath(start, end);
        String totalTravelTime;
        Double totalTime = 0.0;
        //Adds up all the times to get the total time taken
        for (Double time : times) {
            totalTime += time;
        }
        //Converts it to a string representation
        totalTravelTime = "The total travel time is: "+totalTime.toString();

        return "<p>"+"This path starts at "+start+" and ends at "+end+" with the following locations along the path:</p>"
        +"<ol>"+locations.toString()+"</ol>"
        +"<p>"+totalTravelTime+"</p>";	    
    }

    /**
     * Returns an HTML fragment that can be embedded within the body of a
     * larger html page.  This HTML output should include:
     * - a text input field with the id="from", for the start locations
     * - a text input field with the id="time", for the max time limit
     * - a button labelled "Reachable From Within" to submit this request
     * Ensure that these text fields are clearly labelled, so that the user
     * can understand how to use them.
     * @return an HTML string that contains input controls that the user can
     *         make use of to request a ten closest destinations calculation
     */
    @Override
    public String generateReachableFromWithinPromptHTML() {
        //Block of String that contains the HTML for the text inputs and button input as well as the label for the text inputs
        return """
        <label for="from">From:</label>
        <input type="text" id="from"></input>
        <label for="time">Max Time:</label>
        <input type="text" id="time"></input>
        <input type="button" value="Reachable From Within"></input>
                """;
    }
    
    /**
     * Returns an HTML fragment that can be embedded within the body of a
     * larger html page.  This HTML output should include:
     * - a paragraph (p) describing the start location and travel time allowed
     * - an unordered list (ul) of destinations that can be reached within
     *        that allowed travel time
     * Or if no such destinations can be found, the HTML returned should 
     * instead indicate the kind of problem encountered.
     * @param start is the starting location to search from
     * @param travelTime is the maximum number of seconds away from the start
     *        that will allow a destination to be reported
     * @return an HTML string that describes the closest destinations from the
     *         specified start location.
     */    
    @Override
    public String generateReachableFromWithinResponseHTML(String start, double travelTime) {
        StringBuilder reachables = new StringBuilder();
        //backend method of getReachableFromWithin can throw a NoSuchElementException so it is handled here
        try {
		List<String> reachableList = List.of();

            //Only takes in if travelTime isn't 0 or negative
            if (travelTime > 0) {
                //Takes the list of reachable locations as calculated in the backend
                reachableList = backend.getReachableFromWithin(start, travelTime);
            }
	    //If the list is empty no destinations can be found so the HTML returned would represent that
            if (reachableList.isEmpty()) {
                return "<p>There is no locations reachable within the max time or some problem occured.</p>";
            } else {
                //Adding the locations that are reachable and format them as HTML list elements
                for (String reachable: reachableList) {
                    reachables.append("<li>").append(reachable).append("</li>");
                }
            }
        } catch (NoSuchElementException e) { //If an exception is caught then an exception was thrown by the backend which happens when startLocation doesn't exist
            return "Start location does not exist.";
        }

        return "<p>"+"Starting from "+start+" and reachable within the time limit "+travelTime+" seconds are the following:</p>"
        +"<ul>"+reachables.toString()+"</ul>";
    }
}
