// 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.reviewdb.client.RefNames;
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.extensions.events.GitReferenceUpdated;
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.ProjectVersionLogger;
import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper;
import com.googlesource.gerrit.plugins.multisite.forwarder.Context;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
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;

@Singleton
public class ProjectVersionRefUpdate implements EventListener {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
  private static final Set<RefUpdate.Result> SUCCESSFUL_RESULTS =
      ImmutableSet.of(RefUpdate.Result.NEW, RefUpdate.Result.FORCED, RefUpdate.Result.NO_CHANGE);

  public static final String MULTI_SITE_VERSIONING_REF = "refs/multi-site/version";
  public static final String MULTI_SITE_VERSIONING_VALUE_REF = "refs/multi-site/version/value";
  public static final Ref NULL_PROJECT_VERSION_REF =
      new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, MULTI_SITE_VERSIONING_REF, ObjectId.zeroId());

  private final GitRepositoryManager gitRepositoryManager;
  private final GitReferenceUpdated gitReferenceUpdated;
  private final ProjectVersionLogger verLogger;

  protected final SharedRefDatabaseWrapper sharedRefDb;

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

  @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);
    }
  }

  private boolean isSpecialRefName(String refName) {
    return refName.startsWith(RefNames.REFS_SEQUENCES)
        || refName.startsWith(RefNames.REFS_STARRED_CHANGES)
        || refName.equals(MULTI_SITE_VERSIONING_REF);
  }

  private void updateProducerProjectVersionUpdate(RefUpdatedEvent refUpdatedEvent) {
    String refName = refUpdatedEvent.getRefName();

    if (isSpecialRefName(refName)) {
      logger.atFine().log(
          "Found a special ref name %s, skipping update for %s",
          refName, refUpdatedEvent.getProjectNameKey().get());
      return;
    }
    try {
      Project.NameKey projectNameKey = refUpdatedEvent.getProjectNameKey();
      Ref currentProjectVersionRef = getLocalProjectVersionRef(refUpdatedEvent.getProjectNameKey());
      Optional<Long> currentProjectVersionValue =
          getLongFromObjectId(projectNameKey.get(), currentProjectVersionRef.getObjectId());

      Optional<Long> lastRefUpdatedTimestamp = getLastRefUpdatedTimestamp(projectNameKey, refName);
      Optional<ObjectId> newProjectVersionObjectId =
          updateLocalProjectVersion(projectNameKey, lastRefUpdatedTimestamp);

      if (newProjectVersionObjectId.isPresent()) {
        verLogger.log(projectNameKey, lastRefUpdatedTimestamp.get(), 0L);

        updateSharedProjectVersion(
            projectNameKey,
            currentProjectVersionRef,
            newProjectVersionObjectId.get(),
            currentProjectVersionValue,
            lastRefUpdatedTimestamp);
      } else {
        logger.atWarning().log(
            "Ref %s not found on projet %s: skipping project version update",
            refUpdatedEvent.getRefName(), projectNameKey);
      }
    } 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 ref for %s", projectNameKey.get());
      logger.atSevere().withCause(e).log(message);
      throw new LocalProjectVersionUpdateException(message);
    }
  }

  private Optional<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);
      if (ref == null) {
        logger.atWarning().log("Unable to find ref " + refName + " in project " + projectNameKey);
        return Optional.empty();
      }
      try (RevWalk walk = new RevWalk(repository)) {
        RevCommit commit = walk.parseCommit(ref.getObjectId());
        return Optional.of(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,
      Optional<Long> currentVersion,
      Optional<Long> newVersion)
      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);
      if (!success) {
        String message =
            String.format(
                "Project version blob update failed for %s. Current value %s, new value: %s",
                projectNameKey.get(), currentRef.getObjectId(), newObjectId);
        logger.atSevere().log(message);
        throw new SharedProjectVersionUpdateException(message);
      }
      success =
          sharedRefDb.compareAndPut(
              projectNameKey,
              MULTI_SITE_VERSIONING_VALUE_REF,
              currentVersion.map(Object::toString).orElse(null),
              newVersion.map(Object::toString).orElse(null));
      if (!success) {
        String message =
            String.format(
                "Project version update failed for %s. Current value %s, new value: %s",
                projectNameKey.get(), currentRef.getObjectId(), newObjectId);
        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.atFine().log("Local project '%s' has version %d", projectName, repoVersion);
        return Optional.of(repoVersion);
      }
    } catch (RepositoryNotFoundException re) {
      logger.atFine().log("Project '%s' not found", projectName);
    } 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<String> globalVersion =
        sharedRefDb.get(
            Project.NameKey.parse(projectName), MULTI_SITE_VERSIONING_VALUE_REF, String.class);
    return globalVersion.flatMap(longString -> getLongValueOf(longString));
  }

  private Optional<Long> getLongValueOf(String longString) {
    try {
      return Optional.ofNullable(Long.parseLong(longString));
    } catch (NumberFormatException e) {
      logger.atSevere().withCause(e).log(
          "Unable to parse timestamp value %s into Long", longString);
      return Optional.empty();
    }
  }

  private Optional<Long> getLongFromObjectId(String projectName, ObjectId objectId) {
    if (objectId.equals(ObjectId.zeroId())) {
      return Optional.empty();
    }
    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 Optional<ObjectId> updateLocalProjectVersion(
      Project.NameKey projectNameKey, Optional<Long> lastRefUpdatedTimestamp)
      throws LocalProjectVersionUpdateException {
    if (!lastRefUpdatedTimestamp.isPresent()) {
      return Optional.empty();
    }

    logger.atFine().log("Updating local version for project " + projectNameKey.get());
    try (Repository repository = gitRepositoryManager.openRepository(projectNameKey)) {
      RefUpdate refUpdate = getProjectVersionRefUpdate(repository, lastRefUpdatedTimestamp.get());
      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.get());
        logger.atSevere().log(message);
        throw new LocalProjectVersionUpdateException(message);
      }

      gitReferenceUpdated.fire(projectNameKey, refUpdate, null);
      return Optional.of(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 {
    private static final long serialVersionUID = 7649956232401457023L;

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

  public static class SharedProjectVersionUpdateException extends Exception {
    private static final long serialVersionUID = -9153858177700286314L;

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