// 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.batch.ssh;

import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.NoSuchRefException;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gerrit.util.cli.Options;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.batch.Batch;
import com.googlesource.gerrit.plugins.batch.BatchCloser;
import com.googlesource.gerrit.plugins.batch.cli.FastForwardOptions;
import com.googlesource.gerrit.plugins.batch.cli.MergeStrategyOption;
import com.googlesource.gerrit.plugins.batch.cli.PatchSetArgument;
import com.googlesource.gerrit.plugins.batch.util.MergeBranch;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;

@CommandMetaData(
    name = "merge-change",
    description = "Merge changes in the git repository to a batch")
public class MergeChangeCommand extends SshCommand {
  @Inject @Options public MergeStrategyOption strategy;
  @Inject @Options public FastForwardOptions fastForward;

  @Option(
      name = "--message",
      aliases = "-m",
      metaVar = "MESSAGE",
      usage = "commit message to use when applying a change")
  public String message;

  @Option(name = "--close", usage = "close batch on merge success")
  public boolean close;

  protected LinkedHashMap<PatchSet.Id, PatchSetArgument> patchSetArgumentsByPatchSet =
      new LinkedHashMap<PatchSet.Id, PatchSetArgument>();

  @Argument(
      index = 0,
      required = true,
      multiValued = true,
      metaVar = "{CHANGE,PATCHSET}",
      usage = "list of patch sets to merge")
  protected void addPatchSetId(final String token) {
    PatchSetArgument psa = patchSetArgumentFactory.createForArgument(token);
    psa.ensureLatest();
    patchSetArgumentsByPatchSet.put(psa.patchSet.getId(), psa);
  }

  @Inject protected PatchSetArgument.Factory patchSetArgumentFactory;
  @Inject protected MergeBranch.Factory mergeBranchFactory;
  @Inject protected BatchCloser batchCloser;
  @Inject protected ReviewDb db;
  @Inject protected IdentifiedUser user;
  @Inject protected GitRepositoryManager repoManager;
  protected Map<PatchSet.Id, List<ObjectId>> parentsByPsarg =
      new HashMap<PatchSet.Id, List<ObjectId>>();

  @Override
  public void run() throws Exception {
    parseCommandLine();
    Batch batch = new Batch(user.getAccountId());
    String err = null;
    try {
      Resolver resolver = new Resolver(patchSetArgumentsByPatchSet.values());
      for (PatchSetArgument psarg : resolver.resolved) {
        err = "Couldn't merge change(" + psarg.patchSet + ") to batch(" + batch.id + ")";
        merge(batch, psarg.change, psarg.patchSet);
      }
      if (close) {
        err = "Could not close batch(" + batch.id + ")";
        batchCloser.close(batch);
      }
    } catch (Exception e) {
      String msg = e.getMessage();
      if (msg != null) {
        err += ": " + msg;
      }
      throw die(err);
    }
    batch.version = null;
    out.write((OutputFormat.JSON.newGson().toJson(batch) + "\n").getBytes(ENC));
    out.flush();
  }

  protected boolean isParentMergedInto(PatchSetArgument psarg, Iterable<ObjectId> sha1s)
      throws IOException, OrmException, RepositoryNotFoundException {
    for (ObjectId sha1 : sha1s) {
      if (isParentMergedInto(psarg, sha1)) {
        return true;
      }
    }
    return false;
  }

  protected boolean isParentMergedInto(PatchSetArgument psarg, ObjectId sha1)
      throws IOException, OrmException, RepositoryNotFoundException {
    List<ObjectId> parents = getParents(psarg);
    if (parents.isEmpty()) {
      return true;
    }
    for (ObjectId parent : parents) {
      Project.NameKey project = psarg.change.getDest().getParentKey();
      Boolean isMergedInto = isMergedInto(project, parent, sha1);
      if (isMergedInto == null) {
        throw new IOException();
      }
      if (isMergedInto) {
        return true;
      }
    }
    return false;
  }

  public boolean isMergedInto(Project.NameKey project, ObjectId needle, ObjectId haystack)
      throws IOException {
    try (Repository repo = repoManager.openRepository(project);
        RevWalk walk = new RevWalk(repo)) {
      return walk.isMergedInto(walk.parseCommit(needle), walk.parseCommit(haystack));
    }
  }

  protected ObjectId getTip(Branch.NameKey branch)
      throws IOException, NoSuchRefException, RepositoryNotFoundException {
    try (Repository repo = repoManager.openRepository(branch.getParentKey())) {
      Ref ref = repo.getRefDatabase().getRef(branch.get());
      if (ref == null) {
        throw new NoSuchRefException(branch.toString());
      }
      return ref.getObjectId();
    }
  }

  protected void merge(Batch batch, Change change, PatchSet ps)
      throws Exception, IOException, NoSuchRefException, OrmException, UnloggedFailure {
    Branch.NameKey branch = change.getDest();
    Batch.Destination dest = batch.getDestination(branch);
    dest.sha1 =
        mergeBranchFactory
            .create(
                branch,
                dest.sha1,
                ps.getRefName(),
                strategy.getMergeStrategy(),
                fastForward.getFastForwardMode(),
                message)
            .call()
            .getName();
    dest.add(ps.getId());
  }

  /* A Resolver which ensures that changes are eligible to merge before
   * resolving them.  Once resolved, changes are ordered to minimize the
   * amount of merge commits required to merge them.
   */
  protected class Resolver {
    protected class ParentsNotOnBranchException extends Exception {
      private static final long serialVersionUID = 1L;

      protected ParentsNotOnBranchException(PatchSetArgument psarg) {
        super(
            "No Parent of "
                + psarg.patchSet
                + " is on its destination branch("
                + psarg.change.getDest()
                + ")");
      }
    }

    protected class Destination {
      List<PatchSetArgument> remaining = new ArrayList<PatchSetArgument>();
      Set<ObjectId> sources = new HashSet<ObjectId>();

      Destination(Branch.NameKey branch) throws IOException, NoSuchRefException {
        sources.add(getTip(branch));
      }
    }

    protected Map<Branch.NameKey, Destination> destinationsByBranches =
        new HashMap<Branch.NameKey, Destination>();
    protected List<PatchSetArgument> resolved = new ArrayList<PatchSetArgument>();

    protected Resolver(Iterable<PatchSetArgument> psargs)
        throws Exception, IOException, OrmException, NoSuchRefException,
            RepositoryNotFoundException {
      add(psargs);
      while (resolve()) {}
      for (Destination dest : destinationsByBranches.values()) {
        if (!dest.remaining.isEmpty()) {
          throw new ParentsNotOnBranchException(dest.remaining.get(0));
        }
      }
      Collections.reverse(resolved); // Reduces merges
    }

    protected boolean resolve()
        throws IOException, OrmException, NoSuchRefException, RepositoryNotFoundException {
      boolean found = false;
      for (Destination dest : destinationsByBranches.values()) {
        // If more dependencies are destined for the same branch than not,
        // then resolving a branch as much as possible will reduce the
        // total iterations required.
        while (resolve(dest)) {
          found = true;
        }
      }
      return found;
    }

    protected boolean resolve(Destination dest)
        throws IOException, OrmException, NoSuchRefException, RepositoryNotFoundException {
      boolean found = false;
      for (PatchSetArgument psarg : dest.remaining) {
        if (isParentMergedInto(psarg, dest.sources)) {
          found = true;
          resolved.add(psarg);
          dest.sources.add(ObjectId.fromString(psarg.patchSet.getRevision().get()));
        }
      }
      dest.remaining.removeAll(resolved);
      return found;
    }

    protected void add(Iterable<PatchSetArgument> psargs) throws IOException, NoSuchRefException {
      for (PatchSetArgument psarg : psargs) {
        add(psarg);
      }
    }

    protected void add(PatchSetArgument psarg) throws IOException, NoSuchRefException {
      Branch.NameKey branch = psarg.change.getDest();
      Destination dest = getDestination(branch);
      dest.remaining.add(psarg);
    }

    protected Destination getDestination(Branch.NameKey b) throws IOException, NoSuchRefException {
      Destination dest = destinationsByBranches.get(b);
      if (dest == null) {
        dest = new Destination(b);
        destinationsByBranches.put(b, dest);
      }
      return dest;
    }
  }

  protected List<ObjectId> getParents(PatchSetArgument psarg) throws IOException {
    PatchSet.Id id = psarg.patchSet.getId();
    List<ObjectId> parents = parentsByPsarg.get(id);
    if (parents == null) {
      parents = loadParents(psarg);
      parentsByPsarg.put(id, parents);
    }
    return parents;
  }

  protected List<ObjectId> loadParents(PatchSetArgument psarg) throws IOException {
    try (Repository repo = repoManager.openRepository(psarg.change.getProject());
        RevWalk revWalk = new RevWalk(repo)) {
      List<ObjectId> parents = new ArrayList<ObjectId>();
      ObjectId id = ObjectId.fromString(psarg.patchSet.getRevision().get());
      RevCommit c = revWalk.parseCommit(id);
      for (RevCommit parent : c.getParents()) {
        parents.add(parent);
      }
      return parents;
    }
  }
}
