// 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.backend;

import static com.google.gerrit.plugins.codeowners.backend.CodeOwners.getInvalidCodeOwnerConfigCause;
import static com.google.gerrit.plugins.codeowners.backend.CodeOwnersInternalServerErrorException.newInternalServerError;
import static java.util.Objects.requireNonNull;

import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import java.io.IOException;
import java.util.Optional;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk;

/**
 * Class to scan a branch for code owner config files.
 *
 * <p>Whether the scan includes the code owner config file at the root of {@code refs/meta/config}
 * branch that contains the default code owners for the whole repository can be controlled via
 * {@link #includeDefaultCodeOwnerConfig(boolean)}.
 */
public class CodeOwnerConfigScanner {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  public interface Factory {
    CodeOwnerConfigScanner create();
  }

  private final GitRepositoryManager repoManager;
  private final CodeOwnersPluginConfiguration codeOwnersPluginConfiguration;

  private boolean includeDefaultCodeOwnerConfig = true;

  @Inject
  CodeOwnerConfigScanner(
      GitRepositoryManager repoManager,
      CodeOwnersPluginConfiguration codeOwnersPluginConfiguration) {
    this.repoManager = repoManager;
    this.codeOwnersPluginConfiguration = codeOwnersPluginConfiguration;
  }

  /**
   * Whether the scan should include the code owner config file at the root of {@code
   * refs/meta/config} branch that contains the default code owners for the whole repository.
   */
  public CodeOwnerConfigScanner includeDefaultCodeOwnerConfig(
      boolean includeDefaultCodeOwnerConfig) {
    this.includeDefaultCodeOwnerConfig = includeDefaultCodeOwnerConfig;
    return this;
  }

  /**
   * Visits all code owner config files in the given project and branch.
   *
   * @param branchNameKey the project and branch for which the code owner config files should be
   *     visited
   * @param codeOwnerConfigVisitor the callback that is invoked for each code owner config file
   * @param invalidCodeOwnerConfigCallback callback that is invoked for invalid code owner config
   *     files
   */
  public void visit(
      BranchNameKey branchNameKey,
      CodeOwnerConfigVisitor codeOwnerConfigVisitor,
      InvalidCodeOwnerConfigCallback invalidCodeOwnerConfigCallback) {
    visit(
        branchNameKey,
        codeOwnerConfigVisitor,
        invalidCodeOwnerConfigCallback,
        /* pathGlob= */ null);
  }

  /**
   * Visits all code owner config files in the given project and branch.
   *
   * @param branchNameKey the project and branch for which the code owner config files should be
   *     visited
   * @param codeOwnerConfigVisitor the callback that is invoked for each code owner config file
   * @param invalidCodeOwnerConfigCallback callback that is invoked for invalid code owner config
   *     files
   * @param pathGlob optional Java NIO glob that the paths of code owner config files must match
   */
  public void visit(
      BranchNameKey branchNameKey,
      CodeOwnerConfigVisitor codeOwnerConfigVisitor,
      InvalidCodeOwnerConfigCallback invalidCodeOwnerConfigCallback,
      @Nullable String pathGlob) {
    requireNonNull(branchNameKey, "branchNameKey");
    requireNonNull(codeOwnerConfigVisitor, "codeOwnerConfigVisitor");
    requireNonNull(invalidCodeOwnerConfigCallback, "invalidCodeOwnerConfigCallback");

    CodeOwnerBackend codeOwnerBackend =
        codeOwnersPluginConfiguration
            .getProjectConfig(branchNameKey.project())
            .getBackend(branchNameKey.branch());
    logger.atFine().log(
        "scanning code owner files in branch %s of project %s (path glob = %s)",
        branchNameKey.branch(), branchNameKey.project(), pathGlob);

    if (includeDefaultCodeOwnerConfig && !RefNames.REFS_CONFIG.equals(branchNameKey.branch())) {
      logger.atFine().log("Scanning code owner config file in %s", RefNames.REFS_CONFIG);
      Optional<CodeOwnerConfig> metaCodeOwnerConfig =
          codeOwnerBackend.getCodeOwnerConfig(
              CodeOwnerConfig.Key.createWithFileName(
                  codeOwnerBackend, branchNameKey.project(), RefNames.REFS_CONFIG, "/"),
              /** revision */
              null);
      if (metaCodeOwnerConfig.isPresent()) {
        boolean visitFurtherCodeOwnerConfigFiles =
            codeOwnerConfigVisitor.visit(metaCodeOwnerConfig.get());
        if (!visitFurtherCodeOwnerConfigFiles) {
          // By returning false the callback told us to not visit any further code owner config
          // files, hence we are done and do not need to search for further code owner config files
          // in the branch.
          return;
        }
      }
    }

    try (Repository repository = repoManager.openRepository(branchNameKey.project());
        RevWalk rw = new RevWalk(repository);
        CodeOwnerConfigTreeWalk treeWalk =
            new CodeOwnerConfigTreeWalk(
                codeOwnerBackend, branchNameKey, repository, rw, pathGlob)) {
      while (treeWalk.next()) {
        CodeOwnerConfig codeOwnerConfig;
        try {
          codeOwnerConfig = treeWalk.getCodeOwnerConfig();
        } catch (CodeOwnersInternalServerErrorException codeOwnersInternalServerErrorException) {
          Optional<InvalidCodeOwnerConfigException> invalidCodeOwnerConfigException =
              getInvalidCodeOwnerConfigCause(codeOwnersInternalServerErrorException);
          if (!invalidCodeOwnerConfigException.isPresent()) {
            // Propagate any failure that is not related to the contents of the code owner config.
            throw codeOwnersInternalServerErrorException;
          }

          // The code owner config is invalid and cannot be parsed.
          invalidCodeOwnerConfigCallback.onInvalidCodeOwnerConfig(
              treeWalk.getFilePath(), invalidCodeOwnerConfigException.get());
          continue;
        }

        boolean visitFurtherCodeOwnerConfigFiles = codeOwnerConfigVisitor.visit(codeOwnerConfig);
        if (!visitFurtherCodeOwnerConfigFiles) {
          break;
        }
      }
    } catch (IOException e) {
      throw newInternalServerError(
          String.format(
              "Failed to scan for code owner configs in branch %s of project %s",
              branchNameKey.branch(), branchNameKey.project()),
          e);
    }
  }

  /**
   * Returns an {@link InvalidCodeOwnerConfigCallback} instance that ignores invalid code owner
   * config files.
   */
  public static InvalidCodeOwnerConfigCallback ignoreInvalidCodeOwnerConfigFiles() {
    return (codeOwnerConfigFilePath, configInvalidException) ->
        logger.atFine().log("ignoring invalid code owner config file %s", codeOwnerConfigFilePath);
  }
}
