// Copyright (C) 2014 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.server;

import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;

import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
import com.google.gerrit.entities.Comment;
import com.google.gerrit.entities.HumanComment;
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.entities.RobotComment;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.GerritServerId;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.DiffOptions;
import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.query.change.ChangeNumberVirtualIdAlgorithm;
import com.google.gerrit.server.update.ChangeContext;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;

/** Utility functions to manipulate Comments. */
@Singleton
public class CommentsUtil {
  public static final Ordering<Comment> COMMENT_ORDER =
      new Ordering<>() {
        @Override
        public int compare(Comment c1, Comment c2) {
          return ComparisonChain.start()
              .compare(c1.key.filename, c2.key.filename)
              .compare(c1.key.patchSetId, c2.key.patchSetId)
              .compare(c1.side, c2.side)
              .compare(c1.lineNbr, c2.lineNbr)
              .compare(c1.writtenOn, c2.writtenOn)
              .result();
        }
      };

  public static final Ordering<CommentInfo> COMMENT_INFO_ORDER =
      new Ordering<>() {
        @Override
        public int compare(CommentInfo a, CommentInfo b) {
          return ComparisonChain.start()
              .compare(a.path, b.path, NULLS_FIRST)
              .compare(a.patchSet, b.patchSet, NULLS_FIRST)
              .compare(side(a), side(b))
              .compare(a.line, b.line, NULLS_FIRST)
              .compare(a.inReplyTo, b.inReplyTo, NULLS_FIRST)
              .compare(a.message, b.message)
              .compare(a.id, b.id)
              .result();
        }

        private int side(CommentInfo c) {
          return firstNonNull(c.side, Side.REVISION).ordinal();
        }
      };

  public static PatchSet.Id getCommentPsId(Change.Id changeId, Comment comment) {
    return PatchSet.id(changeId, comment.key.patchSetId);
  }

  @Nullable
  public static String extractMessageId(@Nullable String tag) {
    if (tag == null || !tag.startsWith("mailMessageId=")) {
      return null;
    }
    return tag.substring("mailMessageId=".length());
  }

  private static final Ordering<Comparable<?>> NULLS_FIRST = Ordering.natural().nullsFirst();

  private final DiffOperations diffOperations;
  private final GitRepositoryManager repoManager;
  private final AllUsersName allUsers;
  private final String serverId;
  private final ChangeNumberVirtualIdAlgorithm virtualIdAlgorithm;

  @Inject
  CommentsUtil(
      DiffOperations diffOperations,
      GitRepositoryManager repoManager,
      AllUsersName allUsers,
      @GerritServerId String serverId,
      @Nullable ChangeNumberVirtualIdAlgorithm virtualIdAlgorithm) {
    this.diffOperations = diffOperations;
    this.repoManager = repoManager;
    this.allUsers = allUsers;
    this.serverId = serverId;
    this.virtualIdAlgorithm = virtualIdAlgorithm;
  }

  public HumanComment newHumanComment(
      ChangeNotes changeNotes,
      CurrentUser currentUser,
      Instant when,
      String path,
      PatchSet.Id psId,
      short side,
      String message,
      @Nullable Boolean unresolved,
      @Nullable String parentUuid) {
    if (unresolved == null) {
      if (parentUuid == null) {
        // Default to false if comment is not descended from another.
        unresolved = false;
      } else {
        // Inherit unresolved value from inReplyTo comment if not specified.
        Comment.Key key = new Comment.Key(parentUuid, path, psId.get());
        Optional<HumanComment> parent = getPublishedHumanComment(changeNotes, key);

        // If the comment was not found, it is descended from a robot comment, or the UUID is
        // invalid. Either way, we use the default.
        unresolved = parent.map(p -> p.unresolved).orElse(false);
      }
    }
    HumanComment c =
        new HumanComment(
            new Comment.Key(ChangeUtil.messageUuid(), path, psId.get()),
            currentUser.getAccountId(),
            when,
            side,
            message,
            serverId,
            unresolved);
    c.parentUuid = parentUuid;
    currentUser.updateRealAccountId(c::setRealAuthor);
    return c;
  }

  public RobotComment newRobotComment(
      ChangeContext ctx,
      String path,
      PatchSet.Id psId,
      short side,
      String message,
      String robotId,
      String robotRunId) {
    RobotComment c =
        new RobotComment(
            new Comment.Key(ChangeUtil.messageUuid(), path, psId.get()),
            ctx.getUser().getAccountId(),
            ctx.getWhen(),
            side,
            message,
            serverId,
            robotId,
            robotRunId);
    ctx.getUser().updateRealAccountId(c::setRealAuthor);
    return c;
  }

  public Optional<HumanComment> getPublishedHumanComment(ChangeNotes notes, Comment.Key key) {
    return publishedHumanCommentsByChange(notes).stream()
        .filter(c -> key.equals(c.key))
        .findFirst();
  }

  public Optional<HumanComment> getPublishedHumanComment(ChangeNotes notes, String uuid) {
    return publishedHumanCommentsByChange(notes).stream()
        .filter(c -> c.key.uuid.equals(uuid))
        .findFirst();
  }

  public List<HumanComment> publishedHumanCommentsByChange(ChangeNotes notes) {
    notes.load();
    return sort(Lists.newArrayList(notes.getHumanComments().values()));
  }

  public List<RobotComment> robotCommentsByChange(ChangeNotes notes) {
    notes.load();
    return sort(Lists.newArrayList(notes.getRobotComments().values()));
  }

  public Optional<RobotComment> getRobotComment(ChangeNotes notes, String uuid) {
    return robotCommentsByChange(notes).stream().filter(c -> c.key.uuid.equals(uuid)).findFirst();
  }

  public List<HumanComment> publishedByChangeFile(ChangeNotes notes, String file) {
    return commentsOnFile(notes.load().getHumanComments().values(), file);
  }

  public List<HumanComment> publishedByPatchSet(ChangeNotes notes, PatchSet.Id psId) {
    return removeCommentsOnAncestorOfCommitMessage(
        commentsOnPatchSet(notes.load().getHumanComments().values(), psId));
  }

  public List<RobotComment> robotCommentsByPatchSet(ChangeNotes notes, PatchSet.Id psId) {
    return commentsOnPatchSet(notes.load().getRobotComments().values(), psId);
  }

  /**
   * This method populates the "changeMessageId" field of the comments parameter based on timestamp
   * matching. The comments objects will be modified.
   *
   * <p>Each comment will be matched to the nearest next change message in timestamp
   *
   * @param comments the list of comments
   * @param changeMessages list of change messages
   */
  public static void linkCommentsToChangeMessages(
      List<? extends CommentInfo> comments,
      List<ChangeMessage> changeMessages,
      boolean skipAutoGeneratedMessages) {

    // First sort by timestamp, then by authorId so that we could move on to the next change message
    // in case multiple accounts left comments at the same timestamp.
    ArrayList<ChangeMessage> sortedChangeMessages =
        changeMessages.stream()
            .sorted(
                comparing(ChangeMessage::getWrittenOn)
                    .thenComparingInt(c -> c.getAuthor() == null ? 0 : c.getAuthor().get()))
            .collect(toCollection(ArrayList::new));

    ArrayList<CommentInfo> sortedCommentInfos =
        comments.stream()
            .sorted(
                comparing(CommentInfo::getUpdated)
                    .thenComparingInt(c -> c.author == null ? 0 : c.author._accountId))
            .collect(toCollection(ArrayList::new));

    int cmItr = 0;
    int lastMatch = 0;
    for (CommentInfo comment : sortedCommentInfos) {
      // Keep advancing the change message pointer until we associate the comment to the next change
      // message in timestamp
      while (cmItr < sortedChangeMessages.size()) {
        ChangeMessage cm = sortedChangeMessages.get(cmItr);
        if (isAfter(comment, cm)
            || !haveSameAuthor(cm, comment)
            || (skipAutoGeneratedMessages && isAutoGenerated(cm))) {
          cmItr += 1;
        } else {
          lastMatch = cmItr;
          break;
        }
      }
      if (cmItr < changeMessages.size()) {
        comment.changeMessageId = sortedChangeMessages.get(cmItr).getKey().uuid();
      } else {
        // In case of no match "cmItr" will never be less than "changeMessages" size, hence the
        // changeMessageId won't be set for any comment.
        //
        // Reset the search to the last succesful match, since we can't assume there will always be
        // a match between change messages and comments. This could be the case of imported changes.
        //
        // More details here: https://issues.gerritcodereview.com/issues/318079520
        cmItr = lastMatch;
      }
    }
  }

  private static boolean isAutoGenerated(ChangeMessage cm) {
    // Ignore Gerrit auto-generated messages, allowing to link against human change messages that
    // have an auto-generated tag
    return ChangeMessagesUtil.isAutogeneratedByGerrit(cm.getTag());
  }

  private static boolean isAfter(CommentInfo c, ChangeMessage cm) {
    return c.getUpdated().isAfter(cm.getWrittenOn());
  }

  private static boolean haveSameAuthor(ChangeMessage cm, CommentInfo comment) {
    return Objects.equals(
        Optional.ofNullable(cm.getAuthor()).map(a -> a.get()),
        Optional.ofNullable(comment.author).map(a -> a._accountId));
  }
  /**
   * For the commit message the A side in a diff view is always empty when a comparison against an
   * ancestor is done, so there can't be any comments on this ancestor. However earlier we showed
   * the auto-merge commit message on side A when for a merge commit a comparison against the
   * auto-merge was done. From that time there may still be comments on the auto-merge commit
   * message and those we want to filter out.
   */
  private List<HumanComment> removeCommentsOnAncestorOfCommitMessage(List<HumanComment> list) {
    return list.stream()
        .filter(c -> c.side != 0 || !Patch.COMMIT_MSG.equals(c.key.filename))
        .collect(toList());
  }

  public List<HumanComment> draftByPatchSetAuthor(
      PatchSet.Id psId, Account.Id author, ChangeNotes notes) {
    return commentsOnPatchSet(notes.load().getDraftComments(author, getVirtualId(notes)), psId);
  }

  public List<HumanComment> draftByChangeAuthor(ChangeNotes notes, Account.Id author) {
    List<HumanComment> comments = new ArrayList<>();
    comments.addAll(notes.getDraftComments(author, getVirtualId(notes)));
    return sort(comments);
  }

  public void putHumanComments(
      ChangeUpdate update, Comment.Status status, Iterable<HumanComment> comments) {
    for (HumanComment c : comments) {
      update.putComment(status, c);
    }
  }

  public void putRobotComments(ChangeUpdate update, Iterable<RobotComment> comments) {
    for (RobotComment c : comments) {
      update.putRobotComment(c);
    }
  }

  public void deleteHumanComments(ChangeUpdate update, Iterable<HumanComment> comments) {
    for (HumanComment c : comments) {
      update.deleteComment(c);
    }
  }

  public void deleteCommentByRewritingHistory(
      ChangeUpdate update, Comment.Key commentKey, String newMessage) {
    update.deleteCommentByRewritingHistory(commentKey.uuid, newMessage);
  }

  private static List<HumanComment> commentsOnFile(
      Collection<HumanComment> allComments, String file) {
    List<HumanComment> result = new ArrayList<>(allComments.size());
    for (HumanComment c : allComments) {
      String currentFilename = c.key.filename;
      if (currentFilename.equals(file)) {
        result.add(c);
      }
    }
    return sort(result);
  }

  private static <T extends Comment> List<T> commentsOnPatchSet(
      Collection<T> allComments, PatchSet.Id psId) {
    List<T> result = new ArrayList<>(allComments.size());
    for (T c : allComments) {
      if (c.key.patchSetId == psId.get()) {
        result.add(c);
      }
    }
    return sort(result);
  }

  public void setCommentCommitId(Comment c, Change change, PatchSet ps) {
    if (c.getCommitId() == null) {
      checkArgument(
          c.key.patchSetId == ps.id().get(),
          "cannot set commit ID for patch set %s on comment %s",
          ps.id(),
          c);

      // This code is very much down into our stack and shouldn't be used for validation. Hence,
      // don't throw an exception here if we can't find a commit for the indicated side but
      // simply use the all-null ObjectId.
      c.setCommitId(determineCommitId(change, ps, c.side).orElseGet(ObjectId::zeroId));
    }
  }

  /**
   * Determines the SHA-1 of the commit referenced by the (change, patchset, side) triple.
   *
   * @param change the change to which the commit belongs
   * @param patchset the patchset to which the commit belongs
   * @param side the side indicating which commit of the patchset to take. 1 is the patchset commit,
   *     0 the parent commit (or auto-merge for changes representing merge commits); -x the xth
   *     parent commit of a merge commit
   * @return the commit SHA-1 or an empty {@link Optional} if the side isn't available for the given
   *     change/patchset
   * @throws StorageException if the SHA-1 is unavailable for an unknown reason
   */
  public Optional<ObjectId> determineCommitId(Change change, PatchSet patchset, short side) {
    if (Side.fromShort(side) == Side.PARENT) {
      if (side < 0) {
        int parentNumber = Math.abs(side);
        return resolveParentCommit(change.getProject(), patchset, parentNumber);
      }
      return Optional.ofNullable(resolveAutoMergeCommit(change, patchset));
    }
    return Optional.of(patchset.commitId());
  }

  private Optional<ObjectId> resolveParentCommit(
      Project.NameKey project, PatchSet patchset, int parentNumber) {
    try (Repository repository = repoManager.openRepository(project)) {
      RevCommit commit = repository.parseCommit(patchset.commitId());
      if (commit.getParentCount() < parentNumber) {
        return Optional.empty();
      }
      return Optional.of(commit.getParent(parentNumber - 1));
    } catch (IOException e) {
      throw new StorageException(e);
    }
  }

  @Nullable
  private ObjectId resolveAutoMergeCommit(Change change, PatchSet patchset) {
    try {
      // TODO(ghareeb): Adjust after the auto-merge code was moved out of the diff caches. Also
      // unignore the test in PortedCommentsIT.
      Map<String, FileDiffOutput> modifiedFiles =
          diffOperations.listModifiedFilesAgainstParent(
              change.getProject(), patchset.commitId(), /* parentNum= */ 0, DiffOptions.DEFAULTS);
      return modifiedFiles.isEmpty()
          ? null
          : modifiedFiles.values().iterator().next().oldCommitId();
    } catch (DiffNotAvailableException e) {
      throw new StorageException(e);
    }
  }

  /**
   * Get NoteDb draft refs for a change.
   *
   * <p>This is just a simple ref scan, so the results may potentially include refs for zombie draft
   * comments. A zombie draft is one which has been published but the write to delete the draft ref
   * from All-Users failed.
   *
   * @param changeId change ID.
   * @return raw refs from All-Users repo.
   */
  public Collection<Ref> getDraftRefs(Change.Id changeId) {
    try (Repository repo = repoManager.openRepository(allUsers)) {
      return getDraftRefs(repo, changeId);
    } catch (IOException e) {
      throw new StorageException(e);
    }
  }

  private Collection<Ref> getDraftRefs(Repository repo, Change.Id virtualId) throws IOException {
    return repo.getRefDatabase().getRefsByPrefix(RefNames.refsDraftCommentsPrefix(virtualId));
  }

  public static <T extends Comment> List<T> sort(List<T> comments) {
    comments.sort(COMMENT_ORDER);
    return comments;
  }

  private Change.Id getVirtualId(ChangeNotes notes) {
    return virtualIdAlgorithm == null
        ? notes.getChangeId()
        : virtualIdAlgorithm.apply(notes.getServerId(), notes.getChangeId());
  }
}
