// Copyright (C) 2021 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 com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;

/**
 * Represents a configuration on request level that matches requests by request type, URI pattern,
 * caller and/or project pattern.
 */
@AutoValue
public abstract class RequestConfig {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  public static ImmutableList<RequestConfig> parseConfigs(Config cfg, String section) {
    ImmutableList.Builder<RequestConfig> requestConfigs = ImmutableList.builder();

    for (String id : cfg.getSubsections(section)) {
      try {
        RequestConfig.Builder requestConfig = RequestConfig.builder(cfg, section, id);
        requestConfig.requestTypes(parseRequestTypes(cfg, section, id));
        requestConfig.requestUriPatterns(parseRequestUriPatterns(cfg, section, id));
        requestConfig.accountIds(parseAccounts(cfg, section, id));
        requestConfig.projectPatterns(parseProjectPatterns(cfg, section, id));
        requestConfigs.add(requestConfig.build());
      } catch (ConfigInvalidException e) {
        logger.atWarning().log("Ignoring invalid %s configuration:\n %s", section, e.getMessage());
      }
    }

    return requestConfigs.build();
  }

  private static ImmutableSet<String> parseRequestTypes(Config cfg, String section, String id) {
    return ImmutableSet.copyOf(cfg.getStringList(section, id, "requestType"));
  }

  private static ImmutableSet<Pattern> parseRequestUriPatterns(
      Config cfg, String section, String id) throws ConfigInvalidException {
    return parsePatterns(cfg, section, id, "requestUriPattern");
  }

  private static ImmutableSet<Account.Id> parseAccounts(Config cfg, String section, String id)
      throws ConfigInvalidException {
    ImmutableSet.Builder<Account.Id> accountIds = ImmutableSet.builder();
    String[] accounts = cfg.getStringList(section, id, "account");
    for (String account : accounts) {
      Optional<Account.Id> accountId = Account.Id.tryParse(account);
      if (!accountId.isPresent()) {
        throw new ConfigInvalidException(
            String.format(
                "Invalid request config ('%s.%s.account = %s'): invalid account ID",
                section, id, account));
      }
      accountIds.add(accountId.get());
    }
    return accountIds.build();
  }

  private static ImmutableSet<Pattern> parseProjectPatterns(Config cfg, String section, String id)
      throws ConfigInvalidException {
    return parsePatterns(cfg, section, id, "projectPattern");
  }

  private static ImmutableSet<Pattern> parsePatterns(
      Config cfg, String section, String id, String name) throws ConfigInvalidException {
    ImmutableSet.Builder<Pattern> patterns = ImmutableSet.builder();
    String[] patternRegExs = cfg.getStringList(section, id, name);
    for (String patternRegEx : patternRegExs) {
      try {
        patterns.add(Pattern.compile(patternRegEx));
      } catch (PatternSyntaxException e) {
        throw new ConfigInvalidException(
            String.format(
                "Invalid request config ('%s.%s.%s = %s'): %s",
                section, id, name, patternRegEx, e.getMessage()));
      }
    }
    return patterns.build();
  }

  /** the config from which this request config was read */
  abstract Config cfg();

  /** the section from which this request config was read */
  abstract String section();

  /** ID of the config, also the subsection from which this request config was read */
  abstract String id();

  /** request types that should be matched */
  abstract ImmutableSet<String> requestTypes();

  /** pattern matching request URIs */
  abstract ImmutableSet<Pattern> requestUriPatterns();

  /** accounts IDs matching calling user */
  abstract ImmutableSet<Account.Id> accountIds();

  /** pattern matching projects names */
  abstract ImmutableSet<Pattern> projectPatterns();

  private static Builder builder(Config cfg, String section, String id) {
    return new AutoValue_RequestConfig.Builder().cfg(cfg).section(section).id(id);
  }

  /**
   * Whether this request config matches a given request.
   *
   * @param requestInfo request info
   * @return whether this request config matches
   */
  boolean matches(RequestInfo requestInfo) {
    // If in the request config request types are set and none of them matches, then the request is
    // not matched.
    if (!requestTypes().isEmpty()
        && requestTypes().stream()
            .noneMatch(type -> type.equalsIgnoreCase(requestInfo.requestType()))) {
      return false;
    }

    // If in the request config request URI patterns are set and none of them matches, then the
    // request is not matched.
    if (!requestUriPatterns().isEmpty()) {
      if (!requestInfo.requestUri().isPresent()) {
        // The request has no request URI, hence it cannot match a request URI pattern.
        return false;
      }

      if (requestUriPatterns().stream()
          .noneMatch(p -> p.matcher(requestInfo.requestUri().get()).matches())) {
        return false;
      }
    }

    // If in the request config accounts are set and none of them matches, then the request is not
    // matched.
    if (!accountIds().isEmpty()) {
      try {
        if (accountIds().stream()
            .noneMatch(id -> id.equals(requestInfo.callingUser().getAccountId()))) {
          return false;
        }
      } catch (UnsupportedOperationException e) {
        // The calling user is not logged in, hence it cannot match an account.
        return false;
      }
    }

    // If in the request config project patterns are set and none of them matches, then the request
    // is not matched.
    if (!projectPatterns().isEmpty()) {
      if (!requestInfo.project().isPresent()) {
        // The request is not for a project, hence it cannot match a project pattern.
        return false;
      }

      if (projectPatterns().stream()
          .noneMatch(p -> p.matcher(requestInfo.project().get().get()).matches())) {
        return false;
      }
    }

    // For any match criteria (request type, request URI pattern, account, project pattern) that
    // was specified in the request config, at least one of the configured value matched the
    // request.
    return true;
  }

  @AutoValue.Builder
  abstract static class Builder {
    abstract Builder cfg(Config cfg);

    abstract Builder section(String section);

    abstract Builder id(String id);

    abstract Builder requestTypes(ImmutableSet<String> requestTypes);

    abstract Builder requestUriPatterns(ImmutableSet<Pattern> requestUriPatterns);

    abstract Builder accountIds(ImmutableSet<Account.Id> accountIds);

    abstract Builder projectPatterns(ImmutableSet<Pattern> projectPatterns);

    abstract RequestConfig build();
  }
}
