// Copyright (C) 2017 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.testing;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.stream.Collectors.toMap;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;
import com.google.gerrit.index.Schema;
import com.google.gerrit.index.SchemaDefinitions;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NavigableMap;
import org.eclipse.jgit.lib.Config;

public class IndexVersions {
  static final String ALL = "all";
  static final String CURRENT = "current";
  static final String PREVIOUS = "previous";

  /**
   * Returns the index versions from {@link IndexVersions#get(SchemaDefinitions)} without the latest
   * schema version.
   *
   * @param schemaDef the schema definition
   * @return the index versions from {@link IndexVersions#get(SchemaDefinitions)} without the latest
   *     schema version
   */
  public static <V> ImmutableList<Integer> getWithoutLatest(SchemaDefinitions<V> schemaDef) {
    List<Integer> schemaVersions = new ArrayList<>(get(schemaDef));
    schemaVersions.remove(Integer.valueOf(schemaDef.getLatest().getVersion()));
    return ImmutableList.copyOf(schemaVersions);
  }

  /**
   * Returns the schema versions against which the query tests should be executed.
   *
   * <p>The schema versions are read from the '<schema-name>_INDEX_VERSIONS' env var if it is set,
   * e.g. 'ACCOUNTS_INDEX_VERSIONS', 'CHANGES_INDEX_VERSIONS', 'GROUPS_INDEX_VERSIONS'.
   *
   * <p>If schema versions were not specified by an env var, they are read from the
   * 'gerrit.index.<schema-name>.versions' system property, e.g. 'gerrit.index.accounts.version',
   * 'gerrit.index.changes.version', 'gerrit.index.groups.version'.
   *
   * <p>As value a comma-separated list of schema versions is expected. {@code current} can be used
   * for the latest schema version and {@code previous} is resolved to the second last schema
   * version. Alternatively the value can also be {@code all} for all schema versions.
   *
   * <p>If schema versions were neither specified by an env var nor by a system property, the
   * current and the second last schema versions are returned. If there is no other schema version
   * than the current schema version, only the current schema version is returned.
   *
   * @param schemaDef the schema definition
   * @return the schema versions against which the query tests should be executed
   * @throws IllegalArgumentException if the value of the env var or system property is invalid or
   *     if any of the specified schema versions doesn't exist
   */
  public static <V> ImmutableList<Integer> get(SchemaDefinitions<V> schemaDef) {
    String envVar = schemaDef.getName().toUpperCase(Locale.US) + "_INDEX_VERSIONS";
    String value = System.getenv(envVar);
    if (!Strings.isNullOrEmpty(value)) {
      return get(schemaDef, "env variable " + envVar, value);
    }

    String systemProperty =
        "gerrit.index." + schemaDef.getName().toLowerCase(Locale.US) + ".versions";
    value = System.getProperty(systemProperty);
    return get(schemaDef, "system property " + systemProperty, value);
  }

  @VisibleForTesting
  static <V> ImmutableList<Integer> get(SchemaDefinitions<V> schemaDef, String name, String value) {
    if (value != null) {
      value = value.trim();
    }

    NavigableMap<Integer, Schema<V>> schemas = schemaDef.getSchemas();
    if (!Strings.isNullOrEmpty(value)) {
      if (ALL.equals(value)) {
        return ImmutableList.copyOf(schemas.keySet());
      }

      ImmutableList.Builder<Integer> versions = ImmutableList.builder();
      for (String s : Splitter.on(',').trimResults().split(value)) {
        if (CURRENT.equals(s)) {
          versions.add(schemaDef.getLatest().getVersion());
        } else if (PREVIOUS.equals(s)) {
          checkArgument(schemaDef.getPrevious() != null, "previous version does not exist");
          versions.add(schemaDef.getPrevious().getVersion());
        } else {
          Integer version = Ints.tryParse(s);
          checkArgument(version != null, "Invalid value for %s: %s", name, s);
          checkArgument(
              schemas.containsKey(version),
              "Index version %s that was specified by %s not found." + " Possible versions are: %s",
              version,
              name,
              schemas.keySet());
          versions.add(version);
        }
      }
      return versions.build();
    }

    ImmutableList.Builder<Integer> schemaVersions = ImmutableList.builderWithExpectedSize(2);
    if (schemaDef.getPrevious() != null) {
      schemaVersions.add(schemaDef.getPrevious().getVersion());
    }
    schemaVersions.add(schemaDef.getLatest().getVersion());
    return schemaVersions.build();
  }

  public static <V> Map<String, Config> asConfigMap(
      SchemaDefinitions<V> schemaDef,
      List<Integer> schemaVersions,
      String testSuiteNamePrefix,
      Config baseConfig) {
    return schemaVersions.stream()
        .collect(
            toMap(
                i -> testSuiteNamePrefix + i,
                i -> {
                  Config cfg = baseConfig;
                  cfg.setInt(
                      "index",
                      "lucene",
                      schemaDef.getName().toLowerCase(Locale.US) + "TestVersion",
                      i);
                  return cfg;
                }));
  }
}
