// Copyright (C) 2008 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.entities;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A message attached to a {@link Change}. This message is persisted in data storage, that is why it
 * must have template form that does not contain Gerrit user identifiable information. Hence, it
 * requires processing to convert it to user-facing form.
 *
 * <p>These messages are normally auto-generated by gerrit operations, but might also incorporate
 * user input.
 */
public final class ChangeMessage {

  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  /** Template to identify an account in {@link ChangeMessage#message}. */
  public static final String ACCOUNT_TEMPLATE = "<GERRIT_ACCOUNT_%d>";

  public static final String ACCOUNT_TEMPLATE_REGEX = "<GERRIT_ACCOUNT_([0-9]+)>";

  public static final Pattern ACCOUNT_TEMPLATE_PATTERN = Pattern.compile(ACCOUNT_TEMPLATE_REGEX);

  public static Key key(Change.Id changeId, String uuid) {
    return new AutoValue_ChangeMessage_Key(changeId, uuid);
  }

  @AutoValue
  public abstract static class Key {
    public abstract Change.Id changeId();

    public abstract String uuid();
  }

  protected Key key;

  /** Who wrote this comment; null if it was written by the Gerrit system. */
  @Nullable protected Account.Id author;

  /** When this comment was drafted. */
  protected Timestamp writtenOn;

  /**
   * The text left by the user or Gerrit system in template form, that is free of Gerrit User
   * Identifiable Information and can be persisted in data storage.
   */
  @Nullable protected String message;

  /** {@link Account.Id}s that are used in {@link #message} template. */
  protected ImmutableSet<Account.Id> accountsInMessage;

  /** Which patchset (if any) was this message generated from? */
  @Nullable protected PatchSet.Id patchset;

  /** Tag associated with change message */
  @Nullable protected String tag;

  /** Real user that added this message on behalf of the user recorded in {@link #author}. */
  @Nullable protected Account.Id realAuthor;

  protected ChangeMessage() {}

  public static ChangeMessage create(
      final ChangeMessage.Key k, @Nullable Account.Id a, Timestamp wo, @Nullable PatchSet.Id psid) {
    return create(k, a, wo, psid, /*messageTemplate=*/ null, /*realAuthor=*/ null, /*tag=*/ null);
  }

  public static ChangeMessage create(
      final ChangeMessage.Key k,
      @Nullable Account.Id a,
      Timestamp wo,
      @Nullable PatchSet.Id psid,
      @Nullable String messageTemplate,
      @Nullable Account.Id realAuthor,
      @Nullable String tag) {
    ChangeMessage message = new ChangeMessage();
    message.key = k;
    message.author = a;
    message.writtenOn = wo;
    message.patchset = psid;
    message.message = messageTemplate;
    message.accountsInMessage =
        messageTemplate == null ? ImmutableSet.of() : parseTemplates(messageTemplate);
    // Use null for same real author, as before the column was added.
    message.realAuthor = Objects.equals(a, realAuthor) ? null : realAuthor;
    message.tag = tag;
    return message;
  }

  /* Returns account ids that are used in {@code messageTemplate}. */
  public static ImmutableSet<Account.Id> parseTemplates(String messageTemplate) {
    Matcher matcher = ACCOUNT_TEMPLATE_PATTERN.matcher(messageTemplate);
    Set<Account.Id> accountsInTemplate = new HashSet<>();
    while (matcher.find()) {
      String accountId = matcher.group(1);
      Optional<Account.Id> parsedAccountId = Account.Id.tryParse(accountId);
      if (parsedAccountId.isPresent()) {
        accountsInTemplate.add(parsedAccountId.get());
      } else {
        logger.atFine().log("Failed to parse accountId from template %s", matcher.group());
      }
    }
    return ImmutableSet.copyOf(accountsInTemplate);
  }

  public ChangeMessage.Key getKey() {
    return key;
  }

  /** If null, the message was written 'by the Gerrit system'. */
  public Account.Id getAuthor() {
    return author;
  }

  public Account.Id getRealAuthor() {
    return realAuthor != null ? realAuthor : getAuthor();
  }

  public Timestamp getWrittenOn() {
    return writtenOn;
  }

  /** Message template, as persisted in data storage. */
  public String getMessage() {
    return message;
  }

  /** Account ids, used in {@link #message} template. */
  public ImmutableSet<Account.Id> getAccountsInMessage() {
    return accountsInMessage == null ? ImmutableSet.of() : accountsInMessage;
  }

  public String getTag() {
    return tag;
  }

  public PatchSet.Id getPatchSetId() {
    return patchset;
  }

  @Override
  public boolean equals(Object o) {
    if (!(o instanceof ChangeMessage)) {
      return false;
    }
    ChangeMessage m = (ChangeMessage) o;
    return Objects.equals(key, m.key)
        && Objects.equals(author, m.author)
        && Objects.equals(writtenOn, m.writtenOn)
        && Objects.equals(message, m.message)
        && Objects.equals(accountsInMessage, m.accountsInMessage)
        && Objects.equals(patchset, m.patchset)
        && Objects.equals(tag, m.tag)
        && Objects.equals(realAuthor, m.realAuthor);
  }

  @Override
  public int hashCode() {
    return Objects.hash(
        key, author, writtenOn, message, accountsInMessage, patchset, tag, realAuthor);
  }

  @Override
  public String toString() {
    return "ChangeMessage{"
        + "key="
        + key
        + ", author="
        + author
        + ", realAuthor="
        + realAuthor
        + ", writtenOn="
        + writtenOn
        + ", patchset="
        + patchset
        + ", tag="
        + tag
        + ", message=["
        + message
        + "], accountsInMessage="
        + accountsInMessage
        + "}";
  }
}
