// Copyright (C) 2020 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.google.gerrit.plugins.codeowners.restapi;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo.ConsistencyProblemInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.plugins.codeowners.api.CheckCodeOwnerConfigFilesInput;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerBackend;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfig;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfigScanner;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.plugins.codeowners.validation.CodeOwnerConfigValidator;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.permissions.ProjectPermission;
import com.google.gerrit.server.project.ProjectResource;
import com.google.gerrit.server.restapi.project.ListBranches;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk;

/**
 * REST endpoint that checks/validates the code owner config files in a project.
 *
 * <p>This REST endpoint handles {@code POST
 * /projects/<project-name>/branches/<branch-name>/code_owners.check_config} requests.
 *
 * <p>The implementation of this REST endpoint iterates over all code owner config files in the
 * project. This means the expected performance of this REST endpoint is rather low and it should
 * not be used in any critical path where performance matters.
 */
@Singleton
public class CheckCodeOwnerConfigFiles
    implements RestModifyView<ProjectResource, CheckCodeOwnerConfigFilesInput> {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  private final Provider<CurrentUser> currentUser;
  private final PermissionBackend permissionBackend;
  private final GitRepositoryManager repoManager;
  private final Provider<ListBranches> listBranches;
  private final CodeOwnersPluginConfiguration codeOwnersPluginConfiguration;
  private final CodeOwnerConfigScanner.Factory codeOwnerConfigScannerFactory;
  private final CodeOwnerConfigValidator codeOwnerConfigValidator;

  @Inject
  public CheckCodeOwnerConfigFiles(
      Provider<CurrentUser> currentUser,
      PermissionBackend permissionBackend,
      GitRepositoryManager repoManager,
      Provider<ListBranches> listBranches,
      CodeOwnersPluginConfiguration codeOwnersPluginConfiguration,
      CodeOwnerConfigScanner.Factory codeOwnerConfigScannerFactory,
      CodeOwnerConfigValidator codeOwnerConfigValidator) {
    this.currentUser = currentUser;
    this.permissionBackend = permissionBackend;
    this.repoManager = repoManager;
    this.listBranches = listBranches;
    this.codeOwnersPluginConfiguration = codeOwnersPluginConfiguration;
    this.codeOwnerConfigScannerFactory = codeOwnerConfigScannerFactory;
    this.codeOwnerConfigValidator = codeOwnerConfigValidator;
  }

  @Override
  public Response<Map<String, Map<String, List<ConsistencyProblemInfo>>>> apply(
      ProjectResource projectResource, CheckCodeOwnerConfigFilesInput input)
      throws RestApiException, PermissionBackendException, IOException {
    if (!currentUser.get().isIdentifiedUser()) {
      throw new AuthException("Authentication required");
    }

    // This REST endpoint requires the caller to be a project owner.
    permissionBackend
        .currentUser()
        .project(projectResource.getNameKey())
        .check(ProjectPermission.WRITE_CONFIG);

    logger.atFine().log(
        "checking code owner config files for project %s"
            + " (validateDisabledBranches = %s, branches = %s, path = %s, verbosity = %s)",
        projectResource.getNameKey(),
        input.validateDisabledBranches,
        input.branches,
        input.path,
        input.verbosity);

    ImmutableSet<BranchNameKey> branches = branches(projectResource);

    validateInput(projectResource.getNameKey(), branches, input);

    try (Repository repo = repoManager.openRepository(projectResource.getNameKey());
        RevWalk revWalk = new RevWalk(repo)) {
      ImmutableMap.Builder<String, Map<String, List<ConsistencyProblemInfo>>>
          resultsByBranchBuilder = ImmutableMap.builder();
      branches.stream()
          .filter(branchNameKey -> shouldValidateBranch(input, branchNameKey))
          .filter(
              branchNameKey ->
                  validateDisabledBranches(input)
                      || !codeOwnersPluginConfiguration
                          .getProjectConfig(branchNameKey.project())
                          .isDisabled(branchNameKey.branch()))
          .forEach(
              branchNameKey ->
                  resultsByBranchBuilder.put(
                      branchNameKey.branch(),
                      checkBranch(revWalk, input.path, branchNameKey, input.verbosity)));
      return Response.ok(resultsByBranchBuilder.build());
    }
  }

  private ImmutableSet<BranchNameKey> branches(ProjectResource projectResource)
      throws RestApiException, IOException, PermissionBackendException {
    return listBranches.get().apply(projectResource).value().stream()
        .filter(branchInfo -> !"HEAD".equals(branchInfo.ref))
        .map(branchInfo -> BranchNameKey.create(projectResource.getNameKey(), branchInfo.ref))
        .collect(toImmutableSet());
  }

  private Map<String, List<ConsistencyProblemInfo>> checkBranch(
      RevWalk revWalk,
      String pathGlob,
      BranchNameKey branchNameKey,
      @Nullable ConsistencyProblemInfo.Status verbosity) {
    ListMultimap<String, ConsistencyProblemInfo> problemsByPath = LinkedListMultimap.create();
    CodeOwnerBackend codeOwnerBackend =
        codeOwnersPluginConfiguration
            .getProjectConfig(branchNameKey.project())
            .getBackend(branchNameKey.branch());
    codeOwnerConfigScannerFactory
        .create()
        // Do not check the default code owner config file in refs/meta/config, as this config is
        // stored in another branch. If it should be checked users must check the code owner config
        // files in refs/meta/config explicitly.
        .includeDefaultCodeOwnerConfig(false)
        .visit(
            branchNameKey,
            codeOwnerConfig -> {
              problemsByPath.putAll(
                  codeOwnerBackend.getFilePath(codeOwnerConfig.key()).toString(),
                  checkCodeOwnerConfig(
                      branchNameKey.project(),
                      revWalk,
                      codeOwnerBackend,
                      codeOwnerConfig,
                      verbosity));
              return true;
            },
            (codeOwnerConfigFilePath, configInvalidException) -> {
              problemsByPath.put(
                  codeOwnerConfigFilePath.toString(),
                  new ConsistencyProblemInfo(
                      ConsistencyProblemInfo.Status.FATAL, configInvalidException.getMessage()));
            },
            pathGlob);

    return Multimaps.asMap(problemsByPath);
  }

  private ImmutableList<ConsistencyProblemInfo> checkCodeOwnerConfig(
      Project.NameKey project,
      RevWalk revWalk,
      CodeOwnerBackend codeOwnerBackend,
      CodeOwnerConfig codeOwnerConfig,
      @Nullable ConsistencyProblemInfo.Status verbosity) {
    return codeOwnerConfigValidator
        .validateCodeOwnerConfig(
            project,
            revWalk,
            currentUser.get().asIdentifiedUser(),
            codeOwnerBackend,
            codeOwnerConfig)
        .map(
            commitValidationMessage ->
                createConsistencyProblemInfo(commitValidationMessage, verbosity))
        .filter(Optional::isPresent)
        .map(Optional::get)
        .collect(toImmutableList());
  }

  public static Optional<ConsistencyProblemInfo> createConsistencyProblemInfo(
      CommitValidationMessage commitValidationMessage,
      @Nullable ConsistencyProblemInfo.Status verbosity) {
    switch (commitValidationMessage.getType()) {
      case FATAL:
        return Optional.of(
            new ConsistencyProblemInfo(
                ConsistencyProblemInfo.Status.FATAL, commitValidationMessage.getMessage()));
      case ERROR:
        if (ConsistencyProblemInfo.Status.FATAL.equals(verbosity)) {
          // errors should not be reported
          return Optional.empty();
        }
        return Optional.of(
            new ConsistencyProblemInfo(
                ConsistencyProblemInfo.Status.ERROR, commitValidationMessage.getMessage()));
      case WARNING:
        if (ConsistencyProblemInfo.Status.FATAL.equals(verbosity)
            || ConsistencyProblemInfo.Status.ERROR.equals(verbosity)) {
          // warnings should not be reported
          return Optional.empty();
        }
        return Optional.of(
            new ConsistencyProblemInfo(
                ConsistencyProblemInfo.Status.WARNING, commitValidationMessage.getMessage()));
      case HINT:
      case OTHER:
        return Optional.empty();
    }

    throw new IllegalStateException(
        String.format(
            "unknown message type %s for message %s",
            commitValidationMessage.getType(), commitValidationMessage.getMessage()));
  }

  private void validateInput(
      Project.NameKey projectName,
      ImmutableSet<BranchNameKey> branches,
      CheckCodeOwnerConfigFilesInput input)
      throws RestApiException {
    if (input.branches != null) {
      for (String branchName : input.branches) {
        BranchNameKey branchNameKey = BranchNameKey.create(projectName, branchName);
        if (!branches.contains(branchNameKey)) {
          throw new UnprocessableEntityException(String.format("branch %s not found", branchName));
        }

        if ((input.validateDisabledBranches == null || !input.validateDisabledBranches)
            && codeOwnersPluginConfiguration.getProjectConfig(projectName).isDisabled(branchName)) {
          throw new BadRequestException(
              String.format(
                  "code owners functionality for branch %s is disabled,"
                      + " set 'validate_disabled_braches' in the input to 'true' if code owner"
                      + " config files in this branch should be validated",
                  branchName));
        }
      }
    }
  }

  private static boolean shouldValidateBranch(
      CheckCodeOwnerConfigFilesInput input, BranchNameKey branchNameKey) {
    boolean shouldValidateBranch =
        input.branches == null
            || input.branches.contains(branchNameKey.branch())
            || input.branches.contains(branchNameKey.shortName());
    if (!shouldValidateBranch) {
      logger.atFine().log("skip validation for branch %s", branchNameKey.branch());
    }
    return shouldValidateBranch;
  }

  private static boolean validateDisabledBranches(CheckCodeOwnerConfigFilesInput input) {
    return input.validateDisabledBranches != null && input.validateDisabledBranches;
  }
}
