import java.io.IOException;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * This is the frontend class that enables users to access the functionality exposed by the BackendInterface.
 *
 * Notice the organization of the methods below into pairs that generate HTML
 * strings that 1) prompt the user for input to perform a specific computation,
 * and then 2) make use of that input with the help of the backend, to compute
 * and then display the requested results.
 *
 * A webapp will be developed later in this project to integrate these html
 * snippets into a webpage that is returned custom build in response to each
 * user request.
 */
public class Frontend implements FrontendInterface {
  
  private BackendInterface backend;
  
  /**
   * Implementing classes should support the constructor below.
   * @param backend is used for shortest path computations
   */
  public Frontend(BackendInterface backend) {
    // set backend
    this.backend = backend;
    try {
      backend.loadGraphData("campus.dot");
    // catch IOException
    } catch (IOException e) {
      System.out.println("Error loading campus data: " + e.getMessage());
    }
  }

  /**
   * 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() {
    return
    """
      <div>
        <h3>Find Shortest Path</h3>
          <label for="start">Start Location:</label>
          <input type="text" id="start" name="start"><br><br>
          <label for="end">Destination:</label>
          <input type="text" id="end" name="end"><br><br>
          <button onclick="findShortestPath()">Find Shortest Path</button>
      </div>
    """;
  }

  /**
   * 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) {
    try {
      // get shortest path and travel times
      List<String> path = backend.findLocationsOnShortestPath(start, end);
      List<Double> times = backend.findTimesOnShortestPath(start, end);
      
      //no valid routes
      if (path.isEmpty()) return "<p>No path found from " + start + " to " + end + ".</p>";
      
      // make response
      StringBuilder html = new StringBuilder();
      html.append("<div>");
      html.append("<p>Shortest path from ").append(start).append(" to ").append(end).append(":</p>");
      html.append("<ol>");
      // list each location
      for (String loc : path) {
        html.append("<li>").append(loc).append("</li>");
      }
      html.append("</ol>");
      // total travel time
      html.append("<p>Total travel time: ").append(String.format("%.2f", times.get(times.size() - 1))).append(" seconds</p>");
      html.append("</div>");
      return html.toString();
    
    } catch (NoSuchElementException e) {
      // catch if locations are invalid
      return "<p>Error: One or both locations not found in the dataset.</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 location
   * - a button labelled "Furthest Destination From" to submit this request
   * Ensure that this text field is clearly labelled, so that the user
   * can understand how to use it.
   * @return an HTML string that contains input controls that the user can
   *         make use of to request a furthest destination calculation
   */
  @Override
  public String generateFurthestDestinationFromPromptHTML() {
    return
    """
    <div>
        <h3>Find Furthest Destination</h3>
        <!-- labeled input for starting location -->
        <label for="from">Starting Location:</label>
        <input type="text" id="from" name="from"><br><br>
        <!-- button to trigger furthest destination computation -->
      <button onclick="furthestDestinationFrom()">Furthest Destination From</button>
    </div>
    """;
  }

  /**
   * 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 starting point being searched from
   * - a paragraph (p) that describes the furthest destination found
   * - an ordered list (ol) of locations on the path between these locations
   * Or if there is no such destination, the HTML returned should instead
   * indicate the kind of problem encountered.
   * @param start is the starting location to find the furthest dest from
   * @return an HTML string that describes the furthest destination from the
   *        specified start location
   */
  @Override
  public String generateFurthestDestinationFromResponseHTML(String start) {
    try {
      // get shortest path and travel times
      String furthest = backend.getFurthestDestinationFrom(start);
      List<String> path = backend.findLocationsOnShortestPath(start, furthest);
      List<Double> times = backend.findTimesOnShortestPath(start, furthest);
       
      // no valid routes
      if (path.isEmpty())
        return "<p>No reachable destination found from " + start + ".</p>";
      
      // make response
      StringBuilder html = new StringBuilder();
      html.append("<div>");
      html.append("<p>Starting point: ").append(start).append("</p>");
      html.append("<p>Furthest destination: ").append(furthest).append("</p>");
      html.append("<ol>");
      for (String loc : path) {
        html.append("<li>").append(loc).append("</li>");
      }
      html.append("</ol>");
      html.append("<p>Total travel time: ").append(String.format("%.2f", times.get(times.size() - 1))).append(" seconds</p>");
      html.append("</div>");
      return html.toString();
      
    } catch (NoSuchElementException e) {
      // catch if locations are invalid
      return "<p>Error: Could not find a valid destination from " + start + ".</p>";
    }
  }

}
