// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.googlesource.gerrit.plugins.github.wizard;

import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.reviewdb.client.Project.NameKey;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
import com.google.gerrit.server.query.change.ChangeQueryProcessor;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.github.GitHubConfig;
import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.lib.Repository;
import org.kohsuke.github.GHIssueState;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHPullRequestCommitDetail;
import org.kohsuke.github.GHRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class PullRequestListController implements VelocityController {
  private static final Logger LOG = LoggerFactory.getLogger(PullRequestListController.class);
  private static final String DATE_FMT = "yyyy-MM-dd HH:mm z";

  private final GitHubConfig config;
  private final ProjectCache projectsCache;
  private final GitRepositoryManager repoMgr;
  private final Provider<ChangeQueryProcessor> qp;
  private final ChangeQueryBuilder changeQuery;

  @Inject
  public PullRequestListController(
      ProjectCache projectsCache,
      GitRepositoryManager repoMgr,
      GitHubConfig config,
      Provider<ChangeQueryProcessor> qp,
      ChangeQueryBuilder changeQuery) {
    this.projectsCache = projectsCache;
    this.repoMgr = repoMgr;
    this.config = config;
    this.qp = qp;
    this.changeQuery = changeQuery;
  }

  @Override
  public void doAction(
      IdentifiedUser user,
      GitHubLogin hubLogin,
      HttpServletRequest req,
      HttpServletResponse resp,
      ControllerErrors errors)
      throws ServletException, IOException {
    try (PrintWriter out = resp.getWriter()) {
      SimpleDateFormat dateFmt = new SimpleDateFormat(DATE_FMT);
      String organisation = req.getParameter("organisation");
      String repository = req.getParameter("repository");
      Map<String, List<GHPullRequest>> pullRequests =
          getPullRequests(hubLogin, organisation, repository);

      JsonArray reposPullRequests = new JsonArray();
      for (Entry<String, List<GHPullRequest>> repoEntry : pullRequests.entrySet()) {
        JsonObject repoPullRequests = new JsonObject();

        repoPullRequests.add("repository", new JsonPrimitive(repoEntry.getKey()));

        if (repoEntry.getValue() != null) {
          JsonArray prArray = new JsonArray();
          for (GHPullRequest pr : repoEntry.getValue()) {
            JsonObject prObj = new JsonObject();
            prObj.add("id", new JsonPrimitive(new Integer(pr.getNumber())));
            prObj.add("title", new JsonPrimitive(pr.getTitle()));
            prObj.add("body", new JsonPrimitive(pr.getBody()));
            prObj.add(
                "author", new JsonPrimitive(pr.getUser() == null ? "" : pr.getUser().getLogin()));
            prObj.add("status", new JsonPrimitive(pr.getState().name()));
            prObj.add("date", new JsonPrimitive(dateFmt.format(pr.getUpdatedAt())));

            prArray.add(prObj);
          }
          repoPullRequests.add("pullrequests", prArray);
        }

        reposPullRequests.add(repoPullRequests);
      }
      out.println(reposPullRequests.toString());
    }
  }

  private Map<String, List<GHPullRequest>> getPullRequests(
      GitHubLogin hubLogin, String organisation, String repository) throws IOException {
    return getPullRequests(
        hubLogin, projectsCache.byName(organisation + "/" + Strings.nullToEmpty(repository)));
  }

  private Map<String, List<GHPullRequest>> getPullRequests(
      GitHubLogin login, Iterable<NameKey> repos) throws IOException {
    int numPullRequests = 0;
    Map<String, List<GHPullRequest>> allPullRequests = Maps.newHashMap();
    for (NameKey gerritRepoName : repos) {
      try (Repository gitRepo = repoMgr.openRepository(gerritRepoName)) {
        String ghRepoName = gerritRepoName.get().split("/")[1];
        Optional<GHRepository> githubRepo = getGHRepository(login, gerritRepoName);
        if (githubRepo.isPresent()) {
          numPullRequests =
              collectPullRequestsFromGitHubRepository(
                  numPullRequests, allPullRequests, gitRepo, ghRepoName, githubRepo);
        }
      }
    }
    return allPullRequests;
  }

  private int collectPullRequestsFromGitHubRepository(
      int numPullRequests,
      Map<String, List<GHPullRequest>> allPullRequests,
      Repository gitRepo,
      String ghRepoName,
      Optional<GHRepository> githubRepo)
      throws IncorrectObjectTypeException, IOException {
    List<GHPullRequest> repoPullRequests = Lists.newArrayList();

    int count = numPullRequests;
    if (count < config.pullRequestListLimit) {
      for (GHPullRequest ghPullRequest : githubRepo.get().listPullRequests(GHIssueState.OPEN)) {

        if (isAnyCommitOfPullRequestToBeImported(gitRepo, ghPullRequest)) {
          repoPullRequests.add(ghPullRequest);
          count++;
        }
      }
      if (repoPullRequests.size() > 0) {
        allPullRequests.put(ghRepoName, repoPullRequests);
      }
    } else {
      allPullRequests.put(ghRepoName, null);
    }
    return count;
  }

  private Optional<GHRepository> getGHRepository(GitHubLogin login, NameKey gerritRepoName)
      throws IOException {
    try {
      return Optional.of(login.getHub().getRepository(gerritRepoName.get()));
    } catch (FileNotFoundException e) {
      LOG.debug("GitHub repository {} cannot be found", gerritRepoName.get());
      return Optional.absent();
    }
  }

  private boolean isAnyCommitOfPullRequestToBeImported(
      Repository gitRepo, GHPullRequest ghPullRequest)
      throws IncorrectObjectTypeException, IOException {
    boolean pullRequestToImport = false;
    try {
      for (GHPullRequestCommitDetail pullRequestCommit : ghPullRequest.listCommits()) {
        pullRequestToImport |=
            qp.get().query(changeQuery.commit(pullRequestCommit.getSha())).entities().isEmpty();
      }
      return pullRequestToImport;
    } catch (QueryParseException e) {
      LOG.error("Unable to query Gerrit changes for pull-request " + ghPullRequest.getNumber(), e);
      return false;
    }
  }
}
