// Copyright (C) 2018 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.acceptance.testsuite.project;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.gerrit.entities.RefNames.REFS_CONFIG;
import static com.google.gerrit.server.project.ProjectConfig.PROJECT_CONFIG;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Objects.requireNonNull;

import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.TestCapability;
import com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.TestLabelPermission;
import com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.TestPermission;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccessSection;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
import com.google.gerrit.entities.Permission;
import com.google.gerrit.entities.PermissionRule;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.project.CreateProjectArgs;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.server.project.ProjectCreator;
import com.google.inject.Inject;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;

public class ProjectOperationsImpl implements ProjectOperations {
  private final AllProjectsName allProjectsName;
  private final GitRepositoryManager repoManager;
  private final MetaDataUpdate.Server metaDataUpdateFactory;
  private final ProjectCache projectCache;
  private final ProjectConfig.Factory projectConfigFactory;
  private final ProjectCreator projectCreator;

  @Inject
  ProjectOperationsImpl(
      AllProjectsName allProjectsName,
      GitRepositoryManager repoManager,
      MetaDataUpdate.Server metaDataUpdateFactory,
      ProjectCache projectCache,
      ProjectConfig.Factory projectConfigFactory,
      ProjectCreator projectCreator) {
    this.allProjectsName = allProjectsName;
    this.repoManager = repoManager;
    this.metaDataUpdateFactory = metaDataUpdateFactory;
    this.projectCache = projectCache;
    this.projectConfigFactory = projectConfigFactory;
    this.projectCreator = projectCreator;
  }

  @Override
  public TestProjectCreation.Builder newProject() {
    return TestProjectCreation.builder(this::createNewProject);
  }

  private Project.NameKey createNewProject(TestProjectCreation projectCreation) throws Exception {
    String name = projectCreation.name().orElse(RandomStringUtils.randomAlphabetic(8));

    CreateProjectArgs args = new CreateProjectArgs();
    args.setProjectName(name);
    args.permissionsOnly = projectCreation.permissionOnly().orElse(false);
    args.branch =
        projectCreation.branches().stream().map(RefNames::fullName).collect(toImmutableList());
    args.createEmptyCommit = projectCreation.createEmptyCommit().orElse(true);
    projectCreation.parent().ifPresent(p -> args.newParent = p);
    // ProjectCreator wants non-null owner IDs.
    args.ownerIds = new ArrayList<>(projectCreation.owners());
    projectCreation.submitType().ifPresent(st -> args.submitType = st);
    projectCreator.createProject(args);
    return Project.nameKey(name);
  }

  @Override
  public ProjectOperations.PerProjectOperations project(Project.NameKey key) {
    return new PerProjectOperations(key);
  }

  @Override
  public TestProjectUpdate.Builder allProjectsForUpdate() {
    return project(allProjectsName).forUpdate();
  }

  private class PerProjectOperations implements ProjectOperations.PerProjectOperations {
    Project.NameKey nameKey;

    PerProjectOperations(Project.NameKey nameKey) {
      this.nameKey = nameKey;
    }

    @Override
    public RevCommit getHead(String branch) {
      return requireNonNull(headOrNull(branch));
    }

    @Override
    public boolean hasHead(String branch) {
      return headOrNull(branch) != null;
    }

    @Override
    public TestProjectUpdate.Builder forUpdate() {
      return TestProjectUpdate.builder(nameKey, allProjectsName, this::updateProject);
    }

    private void updateProject(TestProjectUpdate projectUpdate)
        throws IOException, ConfigInvalidException {
      try (MetaDataUpdate metaDataUpdate = metaDataUpdateFactory.create(nameKey)) {
        ProjectConfig projectConfig = projectConfigFactory.read(metaDataUpdate);
        if (projectUpdate.removeAllAccessSections()) {
          projectConfig.getAccessSections().forEach(as -> projectConfig.remove(as));
        }
        removePermissions(projectConfig, projectUpdate.removedPermissions());
        addCapabilities(projectConfig, projectUpdate.addedCapabilities());
        addPermissions(projectConfig, projectUpdate.addedPermissions());
        addLabelPermissions(projectConfig, projectUpdate.addedLabelPermissions());
        setExclusiveGroupPermissions(projectConfig, projectUpdate.exclusiveGroupPermissions());
        projectConfig.commit(metaDataUpdate);
      }
      projectCache.evictAndReindex(nameKey);
    }

    private void removePermissions(
        ProjectConfig projectConfig,
        ImmutableList<TestProjectUpdate.TestPermissionKey> removedPermissions) {
      for (TestProjectUpdate.TestPermissionKey p : removedPermissions) {
        projectConfig.upsertAccessSection(
            p.section(),
            as -> {
              Permission.Builder permission = as.upsertPermission(p.name());
              if (p.group().isPresent()) {
                GroupReference group =
                    GroupReference.create(p.group().get(), p.group().get().get());
                group = projectConfig.resolve(group);
                permission.removeRule(group);
              } else {
                permission.clearRules();
              }
            });
      }
    }

    private void addCapabilities(
        ProjectConfig projectConfig, ImmutableList<TestCapability> addedCapabilities) {
      for (TestCapability c : addedCapabilities) {
        PermissionRule.Builder rule = newRule(projectConfig, c.group());
        rule.setRange(c.min(), c.max());
        projectConfig.upsertAccessSection(
            AccessSection.GLOBAL_CAPABILITIES, as -> as.upsertPermission(c.name()).add(rule));
      }
    }

    private void addPermissions(
        ProjectConfig projectConfig, ImmutableList<TestPermission> addedPermissions) {
      for (TestPermission p : addedPermissions) {
        PermissionRule.Builder rule = newRule(projectConfig, p.group());
        rule.setAction(p.action());
        rule.setForce(p.force());
        projectConfig.upsertAccessSection(p.ref(), as -> as.upsertPermission(p.name()).add(rule));
      }
    }

    private void addLabelPermissions(
        ProjectConfig projectConfig, ImmutableList<TestLabelPermission> addedLabelPermissions) {
      for (TestLabelPermission p : addedLabelPermissions) {
        PermissionRule.Builder rule = newRule(projectConfig, p.group());
        rule.setAction(p.action());
        rule.setRange(p.min(), p.max());
        String permissionName;
        if (p.isAddPermission()) {
          permissionName =
              p.impersonation() ? Permission.forLabelAs(p.name()) : Permission.forLabel(p.name());
        } else {
          permissionName = Permission.forRemoveLabel(p.name());
        }
        projectConfig.upsertAccessSection(
            p.ref(), as -> as.upsertPermission(permissionName).add(rule));
      }
    }

    private void setExclusiveGroupPermissions(
        ProjectConfig projectConfig,
        ImmutableMap<TestProjectUpdate.TestPermissionKey, Boolean> exclusiveGroupPermissions) {
      exclusiveGroupPermissions.forEach(
          (key, exclusive) ->
              projectConfig.upsertAccessSection(
                  key.section(),
                  as -> as.upsertPermission(key.name()).setExclusiveGroup(exclusive)));
    }

    @Nullable
    private RevCommit headOrNull(String branch) {
      branch = RefNames.fullName(branch);

      try (Repository repo = repoManager.openRepository(nameKey);
          RevWalk rw = new RevWalk(repo)) {
        Ref r = repo.exactRef(branch);
        return r == null ? null : rw.parseCommit(r.getObjectId());
      } catch (Exception e) {
        throw new IllegalStateException(e);
      }
    }

    @Override
    public ProjectConfig getProjectConfig() {
      try (Repository repo = repoManager.openRepository(nameKey)) {
        ProjectConfig projectConfig = projectConfigFactory.create(nameKey);
        projectConfig.load(nameKey, repo);
        return projectConfig;
      } catch (Exception e) {
        throw new IllegalStateException(e);
      }
    }

    @Override
    public Config getConfig() {
      try (Repository repo = repoManager.openRepository(nameKey);
          RevWalk rw = new RevWalk(repo)) {
        Ref ref = repo.exactRef(REFS_CONFIG);
        if (ref == null) {
          return new Config();
        }
        RevTree tree = rw.parseTree(ref.getObjectId());
        TreeWalk tw = TreeWalk.forPath(rw.getObjectReader(), PROJECT_CONFIG, tree);
        if (tw == null) {
          return new Config();
        }
        ObjectLoader loader = rw.getObjectReader().open(tw.getObjectId(0));
        String text = new String(loader.getCachedBytes(), UTF_8);
        Config config = new Config();
        config.fromText(text);
        return config;
      } catch (Exception e) {
        throw new IllegalStateException(e);
      }
    }

    private void setConfig(Config projectConfig) {
      try (TestRepository<Repository> repo =
          new TestRepository<>(repoManager.openRepository(nameKey))) {
        repo.update(
            RefNames.REFS_CONFIG,
            repo.commit()
                .message("Update project.config from test")
                .parent(getHead(RefNames.REFS_CONFIG))
                .add(ProjectConfig.PROJECT_CONFIG, projectConfig.toText()));
      } catch (Exception e) {
        throw new IllegalStateException(
            "updating project.config of project " + nameKey + " failed", e);
      }
    }

    @Override
    public TestProjectInvalidation.Builder forInvalidation() {
      return TestProjectInvalidation.builder(this::invalidateProject);
    }

    private void invalidateProject(TestProjectInvalidation testProjectInvalidation)
        throws Exception {
      if (testProjectInvalidation.makeProjectConfigInvalid()) {
        Config projectConfig = new Config();
        projectConfig.fromText(getConfig().toText());

        // Make the project config invalid by adding a permission entry with an invalid permission
        // name.
        projectConfig.setString(
            "access", "refs/*", "Invalid Permission Name", "group Administrators");

        setConfig(projectConfig);
        try {
          projectCache.evictAndReindex(nameKey);
        } catch (Exception e) {
          // Evicting the project from the cache, also triggers a reindex of the project.
          // The reindex step fails if the project config is invalid. That's fine, since it was our
          // intention to make the project config invalid. Hence we ignore exceptions that are cause
          // by an invalid project config here.
          if (!Throwables.getCausalChain(e).stream()
              .anyMatch(ConfigInvalidException.class::isInstance)) {
            throw e;
          }
        }
      }
      if (!testProjectInvalidation.projectConfigUpdater().isEmpty()) {
        Config projectConfig = new Config();
        projectConfig.fromText(getConfig().toText());
        testProjectInvalidation.projectConfigUpdater().forEach(c -> c.accept(projectConfig));
        setConfig(projectConfig);
        try {
          projectCache.evictAndReindex(nameKey);
        } catch (Exception e) {
          // Evicting the project from the cache, also triggers a reindex of the project.
          // The reindex step fails if the project config is invalid. That's fine, since it was our
          // intention to make the project config invalid. Hence we ignore exceptions that are cause
          // by an invalid project config here.
          if (!Throwables.getCausalChain(e).stream()
              .anyMatch(ConfigInvalidException.class::isInstance)) {
            throw e;
          }
        }
      }
    }
  }

  private static PermissionRule.Builder newRule(
      ProjectConfig project, AccountGroup.UUID groupUUID) {
    GroupReference group = GroupReference.create(groupUUID, groupUUID.get());
    group = project.resolve(group);
    return PermissionRule.builder(group);
  }
}
