// Copyright (C) 2018 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.quota;

import static com.google.common.base.Preconditions.checkState;

import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.plugincontext.PluginSetEntryContext;
import com.google.gerrit.server.quota.QuotaResponse.Aggregated;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.List;

@Singleton
public class DefaultQuotaBackend implements QuotaBackend {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  private final Provider<CurrentUser> userProvider;
  private final PluginSetContext<QuotaEnforcer> quotaEnforcers;

  @Inject
  DefaultQuotaBackend(
      Provider<CurrentUser> userProvider, PluginSetContext<QuotaEnforcer> quotaEnforcers) {
    this.userProvider = userProvider;
    this.quotaEnforcers = quotaEnforcers;
  }

  @Override
  public WithUser currentUser() {
    return new WithUser(quotaEnforcers, userProvider.get());
  }

  @Override
  public WithUser user(CurrentUser user) {
    return new WithUser(quotaEnforcers, user);
  }

  private static QuotaResponse.Aggregated request(
      PluginSetContext<QuotaEnforcer> quotaEnforcers,
      String quotaGroup,
      QuotaRequestContext requestContext,
      long numTokens,
      boolean deduct) {
    checkState(numTokens > 0, "numTokens must be a positive, non-zero long");

    // PluginSets can change their content when plugins (de-)register. Copy the currently registered
    // plugins so that we can iterate twice on a stable list.
    ImmutableList<PluginSetEntryContext<QuotaEnforcer>> enforcers =
        ImmutableList.copyOf(quotaEnforcers);
    List<QuotaResponse> responses = new ArrayList<>(enforcers.size());
    for (PluginSetEntryContext<QuotaEnforcer> enforcer : enforcers) {
      try {
        if (deduct) {
          responses.add(enforcer.call(p -> p.requestTokens(quotaGroup, requestContext, numTokens)));
        } else {
          responses.add(enforcer.call(p -> p.dryRun(quotaGroup, requestContext, numTokens)));
        }
      } catch (RuntimeException e) {
        // Roll back the quota request for all enforcers that deducted the quota. Rethrow the
        // exception to adhere to the API contract.
        if (deduct) {
          refillAfterErrorOrException(enforcers, responses, quotaGroup, requestContext, numTokens);
        }
        throw e;
      }
    }

    if (deduct && responses.stream().anyMatch(r -> r.status().isError())) {
      // Roll back the quota request for all enforcers that deducted the quota (= the request
      // succeeded). Don't touch failed enforcers as the interface contract said that failed
      // requests should not be deducted.
      refillAfterErrorOrException(enforcers, responses, quotaGroup, requestContext, numTokens);
    }

    logger.atFine().log(
        "Quota request for %s with %s (deduction=%s) for %s token returned %s",
        quotaGroup,
        requestContext,
        deduct ? "(deduction=yes)" : "(deduction=no)",
        numTokens,
        responses);
    return QuotaResponse.Aggregated.create(ImmutableList.copyOf(responses));
  }

  private static QuotaResponse.Aggregated availableTokens(
      PluginSetContext<QuotaEnforcer> quotaEnforcers,
      String quotaGroup,
      QuotaRequestContext requestContext) {
    // PluginSets can change their content when plugins (de-)register. Copy the currently registered
    // plugins so that we can iterate twice on a stable list.
    ImmutableList<PluginSetEntryContext<QuotaEnforcer>> enforcers =
        ImmutableList.copyOf(quotaEnforcers);
    List<QuotaResponse> responses = new ArrayList<>(enforcers.size());
    for (PluginSetEntryContext<QuotaEnforcer> enforcer : enforcers) {
      responses.add(enforcer.call(p -> p.availableTokens(quotaGroup, requestContext)));
    }
    return QuotaResponse.Aggregated.create(responses);
  }

  private static void refillAfterErrorOrException(
      List<PluginSetEntryContext<QuotaEnforcer>> enforcers,
      List<QuotaResponse> collectedResponses,
      String quotaGroup,
      QuotaRequestContext requestContext,
      long numTokens) {
    for (int i = 0; i < collectedResponses.size(); i++) {
      if (collectedResponses.get(i).status().isOk()) {
        enforcers.get(i).run(p -> p.refill(quotaGroup, requestContext, numTokens));
      }
    }
  }

  static class WithUser extends WithResource implements QuotaBackend.WithUser {
    WithUser(PluginSetContext<QuotaEnforcer> quotaEnforcers, CurrentUser user) {
      super(quotaEnforcers, QuotaRequestContext.builder().user(user).build());
    }

    @Override
    public QuotaBackend.WithResource account(Account.Id account) {
      QuotaRequestContext ctx = requestContext.toBuilder().account(account).build();
      return new WithResource(quotaEnforcers, ctx);
    }

    @Override
    public QuotaBackend.WithResource project(Project.NameKey project) {
      QuotaRequestContext ctx = requestContext.toBuilder().project(project).build();
      return new WithResource(quotaEnforcers, ctx);
    }

    @Override
    public QuotaBackend.WithResource change(Change.Id change, Project.NameKey project) {
      QuotaRequestContext ctx = requestContext.toBuilder().change(change).project(project).build();
      return new WithResource(quotaEnforcers, ctx);
    }
  }

  static class WithResource implements QuotaBackend.WithResource {
    protected final QuotaRequestContext requestContext;
    protected final PluginSetContext<QuotaEnforcer> quotaEnforcers;

    private WithResource(
        PluginSetContext<QuotaEnforcer> quotaEnforcers, QuotaRequestContext quotaRequestContext) {
      this.quotaEnforcers = quotaEnforcers;
      this.requestContext = quotaRequestContext;
    }

    @Override
    public QuotaResponse.Aggregated requestTokens(String quotaGroup, long numTokens) {
      return DefaultQuotaBackend.request(
          quotaEnforcers, quotaGroup, requestContext, numTokens, true);
    }

    @Override
    public QuotaResponse.Aggregated dryRun(String quotaGroup, long numTokens) {
      return DefaultQuotaBackend.request(
          quotaEnforcers, quotaGroup, requestContext, numTokens, false);
    }

    @Override
    public Aggregated availableTokens(String quotaGroup) {
      return DefaultQuotaBackend.availableTokens(quotaEnforcers, quotaGroup, requestContext);
    }
  }
}
