package com.google.step.YOUR_PROJECT_NAME_HERE.external;

import com.google.step.YOUR_PROJECT_NAME_HERE.data.Card;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.util.regex.*;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public final class StackOverflowClient {
  private static final String SEARCH_URL_TEMPLATE =
      "https://api.stackexchange.com/2.2/questions/%s?"
          + "order=desc&sort=activity&site=stackoverflow";
  private static final String QUESTION_URL_TEMPLATE =
      "https://api.stackexchange.com/2.2/questions/%s/answers?"
          + "order=desc&sort=votes&site=stackoverflow";
  // This url specify filter to generate answer body.
  private static final String ANSWER_URL_TEMPLATE =
      "https://api.stackexchange.com/2.2/answers/%s?order"
          + "=desc&sort=activity&site=stackoverflow&filter=!9_bDE(fI5";
  private static final int ID_INDEX = 2;
  private static final String ITEM_PARAMETER = "items";
  private static final String TITLE_PARAMETER = "title";
  private static final String BODY_PARAMETER = "body";
  private static final String CODE_PARAMETER = "code";
  private static final String ANSWER_ID_PARAMETER = "answer_id";
  private static final int DESCRIPTION_LENGTH_PARAMETER = 200;

  public Card search(String url) {
    try {
      Card card = getQuestion(url);
      if (card == null) {
        return null;
      }
      card = getAnswerId(card);
      card = getAnswer(card);
      return card;
    } catch (URISyntaxException e) {
      // Return null card if no valid card available.
      return null;
    }
  }

  /* Get the question id based on URL from the CSE result. */
  private Card getQuestion(String url) throws URISyntaxException {
    Card card = new Card();
    URI uri = new URI(url);
    // Parse the URL to get the question id.
    String[] segments = uri.getPath().split("/");
    String questionId = segments[ID_INDEX];
    if(!Pattern.matches("[0-9]+",questionId)) {
      return null;
    }
    String searchUrl = String.format(SEARCH_URL_TEMPLATE, questionId);
    try {
      JSONObject res = getResponse(searchUrl);
      String title =
          res.getJSONArray(ITEM_PARAMETER).getJSONObject(0).get(TITLE_PARAMETER).toString();
      card.setLink(uri.toString());
      // Store the id of the question in order to get the code body of the answer.
      card.setCode(questionId);
      card.setTitle(title);
    } catch (IOException e) {
      e.printStackTrace();
    }
    return card;
  }

  /* Get the most voted answer's id and store it in the card. */
  private Card getAnswerId(Card card) {
    String questionUrl = String.format(QUESTION_URL_TEMPLATE, card.getCode());
    try {
      JSONObject res = getResponse(questionUrl);
      String answerId =
          res.getJSONArray(ITEM_PARAMETER).getJSONObject(0).get(ANSWER_ID_PARAMETER).toString();
      // Replace the question id by the answer id in order to retrieve the code body next.
      card.setCode(answerId);
    } catch (IOException e) {
      e.printStackTrace();
    }
    return card;
  }

  /* Get the content of the answer and store it in the card. */
  private Card getAnswer(Card card) {
    String answerUrl = String.format(ANSWER_URL_TEMPLATE, card.getCode());
    try {
      JSONObject res = getResponse(answerUrl);
      String body =
          res.getJSONArray(ITEM_PARAMETER).getJSONObject(0).get(BODY_PARAMETER).toString();
      Document doc = Jsoup.parse(body);
      // Combine all description in the answer body.
      Elements descriptionHtml = doc.select("p");
      String description = "";
      for (Element e : descriptionHtml) {
        description += e.outerHtml();
      }
      description = description.substring(0, DESCRIPTION_LENGTH_PARAMETER);
      // Combine all code in the answer body.
      Elements codeHtml = doc.select(CODE_PARAMETER);
      String code = "";
      for (Element e : codeHtml) {
        code += e.outerHtml();
      }
      card.setDescription(description);
      card.setCode(code);
    } catch (IOException e) {
      e.printStackTrace();
    }
    return card;
  }

  private JSONObject getResponse(String url) throws IOException {
    CloseableHttpClient httpClient = HttpClients.createDefault();
    CloseableHttpResponse response = httpClient.execute(new HttpGet(url));
    if (response.getStatusLine().getStatusCode() != 200) {
      return new JSONObject();
    }
    HttpEntity entity = response.getEntity();
    if (entity == null) {
      return new JSONObject();
    }
    BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent()));
    StringBuilder responseBody = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
      responseBody.append(line);
    }
    return new JSONObject(responseBody.toString());
  }
}

@@ -2325,16 +2325,17 @@
 ;%0A    if
+ 
 (!Patter
@@ -2353,16 +2353,17 @@
 %5B0-9%5D+%22,
+ 
 question

add validation for question id