// Copyright (C) 2016 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.automerger;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.api.GerritApi;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.re2j.Pattern;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Class to read the config. */
@Singleton
public class ConfigLoader {
  private static final Logger log = LoggerFactory.getLogger(ConfigLoader.class);
  private static final String BRANCH_DELIMITER = ":";
  private static final String DEFAULT_CONFLICT_MESSAGE = "Merge conflict found on ${branch}";

  private final GerritApi gApi;
  private final String pluginName;
  private final String canonicalWebUrl;
  private final AllProjectsName allProjectsName;
  private final PluginConfigFactory cfgFactory;
  private final Provider<CurrentUser> user;

  /**
   * Class to handle getting information from the config.
   *
   * @param gApi API to access gerrit information.
   * @param allProjectsName The name of the top-level project.
   * @param pluginName The name of the plugin we are running.
   * @param cfgFactory Factory to generate the plugin config.
   */
  @Inject
  public ConfigLoader(
      GerritApi gApi,
      AllProjectsName allProjectsName,
      @PluginName String pluginName,
      @CanonicalWebUrl String canonicalWebUrl,
      PluginConfigFactory cfgFactory,
      Provider<CurrentUser> user) {
    this.gApi = gApi;
    this.canonicalWebUrl = canonicalWebUrl;
    this.pluginName = pluginName;
    this.cfgFactory = cfgFactory;
    this.allProjectsName = allProjectsName;
    this.user = user;
  }

  private Config getConfig() throws ConfigInvalidException {
    try {
      return cfgFactory.getProjectPluginConfig(allProjectsName, pluginName);
    } catch (NoSuchProjectException e) {
      throw new ConfigInvalidException(
          "Config invalid because " + allProjectsName.get() + " does not exist!");
    }
  }

  /**
   * Detects whether to skip a change based on the configuration.
   *
   * @param fromBranch Branch we are merging from.
   * @param toBranch Branch we are merging to.
   * @param commitMessage Commit message of the change.
   * @return True if we match blank_merge_regex and merge_all is false, or we match
   *     always_blank_merge_regex
   * @throws ConfigInvalidException
   */
  public boolean isSkipMerge(String fromBranch, String toBranch, String commitMessage)
      throws ConfigInvalidException {
    Pattern alwaysBlankMergePattern = getConfigPattern("alwaysBlankMerge");
    if (alwaysBlankMergePattern.matches(commitMessage)) {
      return true;
    }

    Pattern blankMergePattern = getConfigPattern("blankMerge");
    // If regex matches blank_merge (DO NOT MERGE), skip iff merge_all is false
    if (blankMergePattern.matches(commitMessage)) {
      return !getMergeAll(fromBranch, toBranch);
    }
    return false;
  }

  private Pattern getConfigPattern(String key) throws ConfigInvalidException {
    String[] patternList = getConfig().getStringList("global", null, key);
    Set<String> mergeStrings = new HashSet<>(Arrays.asList(patternList));
    return Pattern.compile(Joiner.on("|").join(mergeStrings), Pattern.DOTALL);
  }

  private boolean getMergeAll(String fromBranch, String toBranch) throws ConfigInvalidException {
    return getConfig()
        .getBoolean("automerger", fromBranch + BRANCH_DELIMITER + toBranch, "mergeAll", false);
  }

  /**
   * Returns the name of the automerge label (i.e. the label to vote -1 if we have a merge conflict)
   *
   * @return Returns the name of the automerge label.
   * @throws ConfigInvalidException
   */
  public String getAutomergeLabel() throws ConfigInvalidException {
    String automergeLabel = getConfig().getString("global", null, "automergeLabel");
    return automergeLabel != null ? automergeLabel : "Code-Review";
  }

  /**
   * Returns the hostName.
   *
   * <p>Uses the hostName defined in the configuration if specified. If not, defaults to the
   * canonicalWebUrl.
   *
   * @return Returns the hostname
   * @throws ConfigInvalidException
   */
  public String getHostName() throws ConfigInvalidException {
    String hostName = getConfig().getString("global", null, "hostName");
    return hostName != null ? hostName : canonicalWebUrl;
  }

  /**
   * Returns a string to append to the end of the merge conflict message.
   *
   * @return The message string, or the empty string if nothing is specified.
   * @throws ConfigInvalidException
   */
  public String getConflictMessage() throws ConfigInvalidException {
    String conflictMessage = getConfig().getString("global", null, "conflictMessage");
    if (Strings.isNullOrEmpty(conflictMessage)) {
      conflictMessage = DEFAULT_CONFLICT_MESSAGE;
    }
    return conflictMessage;
  }

  /**
   * Returns a string to append to the end of the merge conflict message for the manifest project.
   *
   * @return The message string, or the empty string if nothing is specified.
   * @throws ConfigInvalidException
   */
  public String getManifestConflictMessage() throws ConfigInvalidException {
    String conflictMessage = getConfig().getString("global", null, "manifestConflictMessage");
    if (Strings.isNullOrEmpty(conflictMessage)) {
      conflictMessage = getConflictMessage();
    }
    return conflictMessage;
  }

  /**
   * Get the projects that should be merged for the given pair of branches.
   *
   * @param fromBranch Branch we are merging from.
   * @param toBranch Branch we are merging to.
   * @return The projects that are in scope of the given projects.
   * @throws RestApiException
   * @throws IOException
   * @throws ConfigInvalidException
   */
  public Set<String> getProjectsInScope(String fromBranch, String toBranch)
      throws RestApiException, IOException, ConfigInvalidException {
    try {
      Set<String> projectSet = getManifestProjects(fromBranch, toBranch);
      projectSet = applyConfig(fromBranch, toBranch, projectSet);

      log.debug("Project set for {} to {} is {}", fromBranch, toBranch, projectSet);
      return projectSet;
    } catch (RestApiException | IOException e) {
      log.error("Error reading manifest for {}!", fromBranch, e);
      throw e;
    }
  }

  /**
   * Gets the upstream branches of the given branch and project.
   *
   * @param toBranch The downstream branch we would merge to.
   * @param project The project we are merging.
   * @return The branches upstream of the given branch for the given project.
   * @throws RestApiException
   * @throws IOException
   * @throws ConfigInvalidException
   */
  public Set<String> getUpstreamBranches(String toBranch, String project)
      throws ConfigInvalidException, RestApiException, IOException {
    if (toBranch == null) {
      throw new IllegalArgumentException("toBranch cannot be null");
    }
    Set<String> upstreamBranches = new HashSet<>();
    // List all subsections of automerger, split by :
    Set<String> subsections = getConfig().getSubsections(pluginName);
    for (String subsection : subsections) {
      // Subsections are of the form "fromBranch:toBranch"
      List<String> branchPair =
          Splitter.on(BRANCH_DELIMITER).trimResults().omitEmptyStrings().splitToList(subsection);
      if (branchPair.size() != 2) {
        throw new ConfigInvalidException("Automerger config branch pair malformed: " + subsection);
      }
      if (toBranch.equals(branchPair.get(1))) {
        // If toBranch matches, check if project is in both their manifests
        Set<String> projectsInScope = getProjectsInScope(branchPair.get(0), branchPair.get(1));
        if (projectsInScope.contains(project)) {
          upstreamBranches.add(branchPair.get(0));
        }
      }
    }
    return upstreamBranches;
  }

  /**
   * Gets the downstream branches of the given branch and project.
   *
   * @param fromBranch The branch we are merging from.
   * @param project The project we are merging.
   * @return The branches downstream of the given branch for the given project.
   * @throws RestApiException
   * @throws IOException
   * @throws ConfigInvalidException
   */
  public Set<String> getDownstreamBranches(String fromBranch, String project)
      throws RestApiException, IOException, ConfigInvalidException {
    Set<String> downstreamBranches = new HashSet<>();
    // List all subsections of automerger, split by :
    Set<String> subsections = getConfig().getSubsections(pluginName);
    for (String subsection : subsections) {
      // Subsections are of the form "fromBranch:toBranch"
      String[] branchPair = subsection.split(Pattern.quote(BRANCH_DELIMITER));
      if (branchPair.length != 2) {
        throw new ConfigInvalidException("Automerger config branch pair malformed: " + subsection);
      }
      if (fromBranch.equals(branchPair[0])) {
        // If fromBranches match, check if project is in both their manifests
        Set<String> projectsInScope = getProjectsInScope(branchPair[0], branchPair[1]);
        if (projectsInScope.contains(project)) {
          downstreamBranches.add(branchPair[1]);
        }
      }
    }
    return downstreamBranches;
  }

  public Set<String> getAllDownstreamBranches(String branch, String project)
      throws RestApiException, IOException, ConfigInvalidException {
    Set<String> downstreamBranches = new HashSet<>();
    Set<String> immediateDownstreams = getDownstreamBranches(branch, project);
    downstreamBranches.addAll(immediateDownstreams);
    for (String immediateDownstream : immediateDownstreams) {
      downstreamBranches.addAll(getAllDownstreamBranches(immediateDownstream, project));
    }
    return downstreamBranches;
  }

  public String getMissingDownstreamsMessage() throws ConfigInvalidException {
    String message = getConfig().getString("global", null, "missingDownstreamsMessage");
    if (message == null) {
      message =
          "Missing downstream branches ${missingDownstreams}. Please recreate the automerges. "
              + "If your topic contains quotes or braces, please remove them.";
    }
    return message;
  }

  public short getMinAutomergeVote() throws ConfigInvalidException {
    return (short) getConfig().getInt("global", "minAutomergeVote", -2);
  }

  public boolean minAutomergeVoteDisabled() throws ConfigInvalidException {
    return getConfig().getBoolean("global", "disableMinAutomergeVote", false);
  }

  public Account.Id getContextUserId() throws ConfigInvalidException {
    int contextUserId = getConfig().getInt("global", "contextUserId", -1);
    if (contextUserId > 0) {
      return Account.id(contextUserId);
    }
    return user.get().getAccountId();
  }

  /**
   * Returns overriden manifest config if specified, default if not
   *
   * @return The string name of the manifest project.
   * @throws ConfigInvalidException
   */
  public String getManifestProject() throws ConfigInvalidException {
    String manifestProject = getConfig().getString("global", null, "manifestProject");
    if (manifestProject == null) {
      throw new ConfigInvalidException("manifestProject not specified.");
    }
    return manifestProject;
  }

  // Returns overriden manifest config if specified, default if not
  private String getManifestFile() throws ConfigInvalidException {
    String manifestFile = getConfig().getString("global", null, "manifestFile");
    if (manifestFile == null) {
      throw new ConfigInvalidException("manifestFile not specified.");
    }
    return manifestFile;
  }

  // Returns contents of manifest file for the given branch pair
  // If manifest does not exist, return empty set.
  private Set<String> getManifestProjects(String fromBranch, String toBranch)
      throws RestApiException, IOException, ConfigInvalidException {
    boolean ignoreSourceManifest =
        getConfig()
            .getBoolean(
                "automerger",
                fromBranch + BRANCH_DELIMITER + toBranch,
                "ignoreSourceManifest",
                false);

    Set<String> toProjects =
        getProjectsInManifest(getManifestProject(), getManifestFile(), toBranch);
    if (ignoreSourceManifest) {
      return toProjects;
    }

    Set<String> fromProjects =
        getProjectsInManifest(getManifestProject(), getManifestFile(), fromBranch);
    fromProjects.retainAll(toProjects);
    return fromProjects;
  }

  private Set<String> getProjectsInManifest(
      String manifestProject, String manifestFile, String branch)
      throws RestApiException, IOException {
    try (BinaryResult manifestConfig =
        gApi.projects().name(manifestProject).branch(branch).file(manifestFile)) {
      ManifestReader manifestReader = new ManifestReader(branch, manifestConfig.asString());
      return manifestReader.getProjects();
    } catch (ResourceNotFoundException e) {
      log.debug("Manifest for {} not found", branch);
      return new HashSet<>();
    }
  }

  private Set<String> applyConfig(String fromBranch, String toBranch, Set<String> inputProjects)
      throws ConfigInvalidException {
    Set<String> projects = new HashSet<>(inputProjects);
    List<String> setProjects =
        Arrays.asList(
            getConfig()
                .getStringList(
                    "automerger", fromBranch + BRANCH_DELIMITER + toBranch, "setProjects"));
    if (!setProjects.isEmpty()) {
      projects.clear();
      projects.addAll(setProjects);
    }
    List<String> addProjects =
        Arrays.asList(
            getConfig()
                .getStringList(
                    "automerger", fromBranch + BRANCH_DELIMITER + toBranch, "addProjects"));
    projects.addAll(addProjects);
    List<String> ignoreProjects =
        Arrays.asList(
            getConfig()
                .getStringList(
                    "automerger", fromBranch + BRANCH_DELIMITER + toBranch, "ignoreProjects"));
    projects.removeAll(ignoreProjects);
    return projects;
  }
}
