// 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 java.util.Objects.requireNonNull;

import com.google.common.base.Throwables;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.update.RetryHelper;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.regex.Pattern;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk;

/**
 * Base class for all {@link CodeOwnerBackend}'s that store {@link CodeOwnerConfig}'s in files
 * inside the corresponding folders in the source branch.
 *
 * <p>E.g. the code owner configuration for folder {@code /foo/bar} folder of the {@code master}
 * branch is stored as a file in the {@code /foo/bar} folder of the {@code master}
 */
public abstract class AbstractFileBasedCodeOwnerBackend implements CodeOwnerBackend {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  private final CodeOwnersPluginConfiguration codeOwnersPluginConfiguration;
  private final GitRepositoryManager repoManager;
  private final PersonIdent serverIdent;
  private final MetaDataUpdate.InternalFactory metaDataUpdateInternalFactory;
  private final RetryHelper retryHelper;
  private final String defaultFileName;
  private final CodeOwnerConfigParser codeOwnerConfigParser;

  protected AbstractFileBasedCodeOwnerBackend(
      CodeOwnersPluginConfiguration codeOwnersPluginConfiguration,
      GitRepositoryManager repoManager,
      @GerritPersonIdent PersonIdent serverIdent,
      MetaDataUpdate.InternalFactory metaDataUpdateInternalFactory,
      RetryHelper retryHelper,
      String defaultFileName,
      CodeOwnerConfigParser codeOwnerConfigParser) {
    this.codeOwnersPluginConfiguration = codeOwnersPluginConfiguration;
    this.repoManager = repoManager;
    this.serverIdent = serverIdent;
    this.metaDataUpdateInternalFactory = metaDataUpdateInternalFactory;
    this.retryHelper = retryHelper;
    this.defaultFileName = defaultFileName;
    this.codeOwnerConfigParser = codeOwnerConfigParser;
  }

  @Override
  public final Optional<CodeOwnerConfig> getCodeOwnerConfig(
      CodeOwnerConfig.Key codeOwnerConfigKey,
      @Nullable RevWalk revWalk,
      @Nullable ObjectId revision) {
    String fileName =
        codeOwnerConfigKey.fileName().orElse(getFileName(codeOwnerConfigKey.project()));

    if (!isCodeOwnerConfigFile(codeOwnerConfigKey.project(), fileName)) {
      // The file name can mismatch if we resolve imported code owner configs. When code owner
      // configs are imported the user specifies the full path of the code owner config (including
      // the file name) in the importing code owner config. If the user specifies a file name that
      // is not supported, this is not a server error, but a user error. Invalid imports are
      // silently ignored, but users can detect them by running validation checks on the code owner
      // configs. Although this is a normal situation, still log a warning so that we can see in the
      // server logs when this happens.
      logger.atWarning().log(
          "Cannot load code owner config %s: unsupported file name", codeOwnerConfigKey);
      return Optional.empty();
    }

    return loadCodeOwnerConfigFile(codeOwnerConfigKey, fileName, revWalk, revision)
        .getLoadedCodeOwnerConfig();
  }

  private CodeOwnerConfigFile loadCodeOwnerConfigFile(
      CodeOwnerConfig.Key codeOwnerConfigKey,
      String fileName,
      @Nullable RevWalk revWalk,
      @Nullable ObjectId revision) {
    try (Repository repository = repoManager.openRepository(codeOwnerConfigKey.project())) {
      if (revision == null) {
        return CodeOwnerConfigFile.loadCurrent(
            fileName, codeOwnerConfigParser, repository, codeOwnerConfigKey);
      }

      boolean closeRevWalk = false;
      if (revWalk == null) {
        closeRevWalk = true;
        revWalk = new RevWalk(repository);
      }
      try {
        return CodeOwnerConfigFile.load(
            fileName, codeOwnerConfigParser, revWalk, revision, codeOwnerConfigKey);
      } finally {
        if (closeRevWalk) {
          revWalk.close();
        }
      }
    } catch (IOException e) {
      throw new StorageException(
          String.format("failed to load code owner config %s", codeOwnerConfigKey), e);
    } catch (ConfigInvalidException e) {
      throw new StorageException(
          String.format(
              "invalid code owner config file %s (project = %s, branch = %s)",
              codeOwnerConfigKey.filePath(defaultFileName),
              codeOwnerConfigKey.project(),
              codeOwnerConfigKey.branchNameKey().branch()),
          e);
    }
  }

  @Override
  public Path getFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
    return codeOwnerConfigKey.filePath(defaultFileName);
  }

  @Override
  public boolean isCodeOwnerConfigFile(Project.NameKey project, String fileName) {
    requireNonNull(project, "project");
    requireNonNull(fileName, "fileName");

    if (getFileName(project).equals(fileName)) {
      return true;
    }

    return isCodeOwnerConfigFileWithExtension(project, fileName);
  }

  /**
   * Checks whether the given file name is code owner config file with an extension in the name.
   *
   * <p>Name extensions can appear as post- or pre-fix:
   *
   * <ul>
   *   <li>Post-fix: E.g. {@code OWNERS_<extension>} or {@code OWNERS_<extension>.<file-extension>}
   *   <li>Pre-fix: E.g. {@code <extension>_OWNERS} or {@code <extension>_OWNERS.<file-extension>}
   * </ul>
   *
   * @param project the project in which the code owner config files are stored
   * @param fileName the name of the file for which it should be checked whether is a code owner
   *     config file with extension
   * @return whether the given file name is code owner config file with an extension in the name
   */
  private boolean isCodeOwnerConfigFileWithExtension(Project.NameKey project, String fileName) {
    String quotedDefaultFileName = Pattern.quote(defaultFileName);
    String quotedFileExtension =
        Pattern.quote(
            codeOwnersPluginConfiguration
                .getFileExtension(project)
                .map(ext -> "." + ext)
                .orElse(""));
    String nameExtension = "(\\w)+";

    return Pattern.compile(
                "^" + quotedDefaultFileName + "_" + nameExtension + quotedFileExtension + "$")
            .matcher(fileName)
            .matches()
        || Pattern.compile(
                "^" + nameExtension + "_" + quotedDefaultFileName + quotedFileExtension + "$")
            .matcher(fileName)
            .matches();
  }

  private String getFileName(Project.NameKey project) {
    return defaultFileName
        + codeOwnersPluginConfiguration.getFileExtension(project).map(ext -> "." + ext).orElse("");
  }

  @Override
  public final Optional<CodeOwnerConfig> upsertCodeOwnerConfig(
      CodeOwnerConfig.Key codeOwnerConfigKey,
      CodeOwnerConfigUpdate codeOwnerConfigUpdate,
      @Nullable IdentifiedUser currentUser) {
    try {
      return retryHelper
          .pluginUpdate(
              "upsertCodeOwnerConfigInSourceBranch",
              () ->
                  upsertCodeOwnerConfigInSourceBranch(
                      currentUser, codeOwnerConfigKey, codeOwnerConfigUpdate))
          .call();
    } catch (Exception e) {
      Throwables.throwIfUnchecked(e);
      throw new StorageException(e);
    }
  }

  private Optional<CodeOwnerConfig> upsertCodeOwnerConfigInSourceBranch(
      @Nullable IdentifiedUser currentUser,
      CodeOwnerConfig.Key codeOwnerConfigKey,
      CodeOwnerConfigUpdate codeOwnerConfigUpdate) {
    try (Repository repository = repoManager.openRepository(codeOwnerConfigKey.project())) {
      CodeOwnerConfigFile codeOwnerConfigFile =
          CodeOwnerConfigFile.loadCurrent(
                  getFileName(codeOwnerConfigKey.project()),
                  codeOwnerConfigParser,
                  repository,
                  codeOwnerConfigKey)
              .setCodeOwnerConfigUpdate(codeOwnerConfigUpdate);

      try (MetaDataUpdate metaDataUpdate =
          createMetaDataUpdate(codeOwnerConfigKey.project(), repository, currentUser)) {
        codeOwnerConfigFile.commit(metaDataUpdate);
      }

      return codeOwnerConfigFile.getLoadedCodeOwnerConfig();
    } catch (IOException | ConfigInvalidException e) {
      throw new StorageException(
          String.format("failed to upsert code owner config %s", codeOwnerConfigKey), e);
    }
  }

  private MetaDataUpdate createMetaDataUpdate(
      Project.NameKey project, Repository repository, @Nullable IdentifiedUser currentUser) {
    MetaDataUpdate metaDataUpdate = metaDataUpdateInternalFactory.create(project, repository, null);
    try {
      metaDataUpdate.getCommitBuilder().setCommitter(serverIdent);
      if (currentUser != null) {
        // Using MetaDataUpdate#setAuthor copies the timezone and timestamp from the committer
        // identity, so that it's ensured that the author and committer identities have the same
        // timezone and timestamp.
        metaDataUpdate.setAuthor(currentUser);
      } else {
        // In this case the author identity is the same as the committer identity, hence it already
        // has the correct timezone and timestamp and we can set it on the commit builder directly.
        metaDataUpdate.getCommitBuilder().setAuthor(serverIdent);
      }
      return metaDataUpdate;
    } catch (Throwable t) {
      metaDataUpdate.close();
      Throwables.throwIfUnchecked(t);
      throw new StorageException("Failed to create MetaDataUpdate", t);
    }
  }
}
