// 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.googlesource.gerrit.plugins.multisite.validation;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;

import com.gerritforge.gerrit.globalrefdb.GlobalRefDbSystemError;
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.common.primitives.Ints;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.events.EventListener;
import com.google.gerrit.server.events.RefUpdatedEvent;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.IntBlob;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper;
import com.googlesource.gerrit.plugins.multisite.forwarder.Context;
import com.googlesource.gerrit.plugins.replication.RefReplicatedEvent;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.RemoteRefUpdate;

@Singleton
public class ProjectVersionRefUpdate implements EventListener {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
  public static final String MULTI_SITE_VERSIONING_REF = "refs/multi-site/version";
  public static final String SEQUENCE_REF_PREFIX = "refs/sequences/";
  private static final Ref NULL_PROJECT_VERSION_REF =
      new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, MULTI_SITE_VERSIONING_REF, ObjectId.zeroId());
  private static final Set<RefUpdate.Result> SUCCESSFUL_RESULTS =
      ImmutableSet.of(RefUpdate.Result.NEW, RefUpdate.Result.FORCED, RefUpdate.Result.NO_CHANGE);

  protected final SharedRefDatabaseWrapper sharedRefDb;
  private final GitRepositoryManager gitRepositoryManager;

  @Inject
  public ProjectVersionRefUpdate(
      GitRepositoryManager gitRepositoryManager, SharedRefDatabaseWrapper sharedRefDb) {
    this.gitRepositoryManager = gitRepositoryManager;
    this.sharedRefDb = sharedRefDb;
  }

  @Override
  public void onEvent(Event event) {
    logger.atFine().log("Processing event type: " + event.type);
    // Producer of the Event use RefUpdatedEvent to trigger the version update
    if (!Context.isForwardedEvent() && event instanceof RefUpdatedEvent) {
      updateProducerProjectVersionUpdate((RefUpdatedEvent) event);
    }

    // Consumers of the Event use RefReplicatedEvent to trigger the version update
    if (Context.isForwardedEvent() && event instanceof RefReplicatedEvent) {
      updateConsumerProjectVersion((RefReplicatedEvent) event);
    }
  }

  private void updateConsumerProjectVersion(RefReplicatedEvent refReplicatedEvent) {
    Project.NameKey projectNameKey = refReplicatedEvent.getProjectNameKey();
    if (!refReplicatedEvent.refStatus.equals(RemoteRefUpdate.Status.OK)) {
      logger.atFine().log(
          String.format(
              "Skipping version update for %s. RefReplicatedEvent failed with %s",
              projectNameKey.get(), refReplicatedEvent.refStatus));
      return;
    }
    if (refReplicatedEvent.getRefName().startsWith(SEQUENCE_REF_PREFIX)) {
      logger.atFine().log("Found Sequence ref, skipping update for " + projectNameKey.get());
      return;
    }
    try {
      updateLocalProjectVersion(projectNameKey, refReplicatedEvent.getRefName());
    } catch (LocalProjectVersionUpdateException e) {
      logger.atSevere().withCause(e).log(
          "Issue encountered when updating version for project " + projectNameKey);
    }
  }

  private void updateProducerProjectVersionUpdate(RefUpdatedEvent refUpdatedEvent) {
    if (refUpdatedEvent.getRefName().startsWith(SEQUENCE_REF_PREFIX)) {
      logger.atFine().log(
          "Found Sequence ref, skipping update for " + refUpdatedEvent.getProjectNameKey().get());
      return;
    }
    try {
      Project.NameKey projectNameKey = refUpdatedEvent.getProjectNameKey();
      Ref currentProjectVersionRef = getLocalProjectVersionRef(refUpdatedEvent.getProjectNameKey());
      ObjectId newProjectVersionObjectId =
          updateLocalProjectVersion(projectNameKey, refUpdatedEvent.getRefName());
      updateSharedProjectVersion(
          projectNameKey, currentProjectVersionRef, newProjectVersionObjectId);
    } catch (LocalProjectVersionUpdateException | SharedProjectVersionUpdateException e) {
      logger.atSevere().withCause(e).log(
          "Issue encountered when updating version for project "
              + refUpdatedEvent.getProjectNameKey());
    }
  }

  private RefUpdate getProjectVersionRefUpdate(Repository repository, Long version)
      throws IOException {
    RefUpdate refUpdate = repository.getRefDatabase().newUpdate(MULTI_SITE_VERSIONING_REF, false);
    refUpdate.setNewObjectId(getNewId(repository, version));
    refUpdate.setForceUpdate(true);
    return refUpdate;
  }

  private ObjectId getNewId(Repository repository, Long version) throws IOException {
    ObjectInserter ins = repository.newObjectInserter();
    ObjectId newId = ins.insert(OBJ_BLOB, Long.toString(version).getBytes(UTF_8));
    ins.flush();
    return newId;
  }

  private Ref getLocalProjectVersionRef(Project.NameKey projectNameKey)
      throws LocalProjectVersionUpdateException {
    try (Repository repository = gitRepositoryManager.openRepository(projectNameKey)) {
      Ref ref = repository.findRef(MULTI_SITE_VERSIONING_REF);
      return ref != null ? ref : NULL_PROJECT_VERSION_REF;
    } catch (IOException e) {
      String message =
          String.format("Error while getting current version for %s", projectNameKey.get());
      logger.atSevere().withCause(e).log(message);
      throw new LocalProjectVersionUpdateException(message);
    }
  }

  private Long getLastRefUpdatedTimestamp(Project.NameKey projectNameKey, String refName)
      throws LocalProjectVersionUpdateException {
    logger.atFine().log(
        String.format(
            "Getting last ref updated time for project %s, ref %s", projectNameKey.get(), refName));
    try (Repository repository = gitRepositoryManager.openRepository(projectNameKey)) {
      Ref ref = repository.findRef(refName);
      try (RevWalk walk = new RevWalk(repository)) {
        RevCommit commit = walk.parseCommit(ref.getObjectId());
        return Integer.toUnsignedLong(commit.getCommitTime());
      }
    } catch (IOException ioe) {
      String message =
          String.format(
              "Error while getting last ref updated time for project %s, ref %s",
              projectNameKey.get(), refName);
      logger.atSevere().withCause(ioe).log(message);
      throw new LocalProjectVersionUpdateException(message);
    }
  }

  private void updateSharedProjectVersion(
      Project.NameKey projectNameKey, Ref currentRef, ObjectId newObjectId)
      throws SharedProjectVersionUpdateException {
    logger.atFine().log(
        String.format(
            "Updating shared project version for %s. Current value %s, new value: %s",
            projectNameKey.get(), currentRef.getObjectId(), newObjectId));
    try {
      boolean success = sharedRefDb.compareAndPut(projectNameKey, currentRef, newObjectId);
      String message =
          String.format(
              "Project version update failed for %s. Current value %s, new value: %s",
              projectNameKey.get(), currentRef.getObjectId(), newObjectId);
      if (!success) {
        logger.atSevere().log(message);
        throw new SharedProjectVersionUpdateException(message);
      }
    } catch (GlobalRefDbSystemError refDbSystemError) {
      String message =
          String.format(
              "Error while updating shared project version for %s. Current value %s, new value: %s. Error: %s",
              projectNameKey.get(),
              currentRef.getObjectId(),
              newObjectId,
              refDbSystemError.getMessage());
      logger.atSevere().withCause(refDbSystemError).log(message);
      throw new SharedProjectVersionUpdateException(message);
    }
  }

  public Optional<Long> getProjectLocalVersion(String projectName) {
    try (Repository repository =
        gitRepositoryManager.openRepository(Project.NameKey.parse(projectName))) {
      Optional<IntBlob> blob = IntBlob.parse(repository, MULTI_SITE_VERSIONING_REF);
      if (blob.isPresent()) {
        Long repoVersion = Integer.toUnsignedLong(blob.get().value());
        logger.atInfo().log("Local project '%s' has version %d", projectName, repoVersion);
        return Optional.of(repoVersion);
      }
    } catch (IOException e) {
      logger.atSevere().withCause(e).log("Cannot read local project '%s' version", projectName);
    }
    return Optional.empty();
  }

  public Optional<Long> getProjectRemoteVersion(String projectName) {
    Optional<ObjectId> remoteObjectId =
        sharedRefDb.get(
            Project.NameKey.parse(projectName), MULTI_SITE_VERSIONING_REF, ObjectId.class);
    if (remoteObjectId.isPresent()) {
      return getLongFromObjectId(projectName, remoteObjectId.get());
    } else {
      logger.atSevere().log("Didn't find remote version for %s", projectName);
      return Optional.empty();
    }
  }

  private Optional<Long> getLongFromObjectId(String projectName, ObjectId objectId) {
    try (Repository repository =
        gitRepositoryManager.openRepository(Project.NameKey.parse(projectName))) {
      ObjectReader or = repository.newObjectReader();
      ObjectLoader ol = or.open(objectId, OBJ_BLOB);
      if (ol.getType() != OBJ_BLOB) {
        // In theory this should be thrown by open but not all implementations may do it properly
        // (certainly InMemoryRepository doesn't).
        logger.atSevere().log("Incorrect object type loaded for objectId %s", objectId.toString());
        return Optional.empty();
      }
      String str = CharMatcher.whitespace().trimFrom(new String(ol.getCachedBytes(), UTF_8));
      Integer value = Ints.tryParse(str);
      logger.atInfo().log(
          "Found remote version for project %s, value: %s - %d",
          projectName, objectId.toString(), value);
      return Optional.of(Integer.toUnsignedLong(value));
    } catch (IOException e) {
      logger.atSevere().withCause(e).log("Cannot parse objectId %s", objectId.toString());
      return Optional.empty();
    }
  }

  private ObjectId updateLocalProjectVersion(Project.NameKey projectNameKey, String refName)
      throws LocalProjectVersionUpdateException {
    Long lastRefUpdatedTimestamp = getLastRefUpdatedTimestamp(projectNameKey, refName);
    logger.atFine().log("Updating local version for project " + projectNameKey.get());
    try (Repository repository = gitRepositoryManager.openRepository(projectNameKey)) {
      RefUpdate refUpdate = getProjectVersionRefUpdate(repository, lastRefUpdatedTimestamp);
      RefUpdate.Result result = refUpdate.update();
      if (!isSuccessful(result)) {
        String message =
            String.format(
                "RefUpdate failed with result %s for: project=%s, version=%d",
                result.name(), projectNameKey.get(), lastRefUpdatedTimestamp);
        logger.atSevere().log(message);
        throw new LocalProjectVersionUpdateException(message);
      }
      return refUpdate.getNewObjectId();
    } catch (IOException e) {
      String message = "Cannot create versioning command for " + projectNameKey.get();
      logger.atSevere().withCause(e).log(message);
      throw new LocalProjectVersionUpdateException(message);
    }
  }

  private Boolean isSuccessful(RefUpdate.Result result) {
    return SUCCESSFUL_RESULTS.contains(result);
  }

  public static class LocalProjectVersionUpdateException extends Exception {
    public LocalProjectVersionUpdateException(String projectName) {
      super("Cannot update local project version of " + projectName);
    }
  }

  public static class SharedProjectVersionUpdateException extends Exception {
    public SharedProjectVersionUpdateException(String projectName) {
      super("Cannot update shared project version of " + projectName);
    }
  }
}
