// Copyright (C) 2010 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.entities;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.util.Objects.requireNonNull;

import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.gerrit.common.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.regex.Pattern;

/** Portion of a {@link Project} describing access rules. */
@AutoValue
public abstract class AccessSection implements Comparable<AccessSection> {
  /** Special name given to the global capabilities; not a valid reference. */
  public static final String GLOBAL_CAPABILITIES = "GLOBAL_CAPABILITIES";

  /** Pattern that matches all references in a project. */
  public static final String ALL = "refs/*";

  /** Pattern that matches all branches in a project. */
  public static final String HEADS = "refs/heads/*";

  /** Prefix that triggers a regular expression pattern. */
  public static final String REGEX_PREFIX = "^";

  /** Name of the access section. It could be a ref pattern or something else. */
  public abstract String getName();

  /**
   * A compiled regular expression in case {@link #getName()} is a regular expression. This is
   * memoized to save callers from compiling patterns for every use.
   */
  @Memoized
  public Optional<Pattern> getNamePattern() {
    if (isValidRefSectionName(getName())
        && getName().startsWith(REGEX_PREFIX)
        && !getName().contains("${")) {
      return Optional.of(Pattern.compile(getName()));
    }
    return Optional.empty();
  }

  public abstract ImmutableList<Permission> getPermissions();

  public static AccessSection create(String name) {
    return builder(name).build();
  }

  public static Builder builder(String name) {
    return new AutoValue_AccessSection.Builder().setName(name).setPermissions(ImmutableList.of());
  }

  /** Returns true if the name is likely to be a valid reference section name. */
  public static boolean isValidRefSectionName(String name) {
    return name.startsWith("refs/") || name.startsWith("^refs/");
  }

  @Nullable
  public Permission getPermission(String name) {
    requireNonNull(name);
    for (Permission p : getPermissions()) {
      if (p.getName().equalsIgnoreCase(name)) {
        return p;
      }
    }
    return null;
  }

  @Override
  public final int compareTo(AccessSection o) {
    return comparePattern().compareTo(o.comparePattern());
  }

  private String comparePattern() {
    if (getName().startsWith(REGEX_PREFIX)) {
      return getName().substring(REGEX_PREFIX.length());
    }
    return getName();
  }

  @Override
  public final String toString() {
    return "AccessSection[" + getName() + "]";
  }

  public Builder toBuilder() {
    Builder b = autoToBuilder();
    b.getPermissions().stream().map(Permission::toBuilder).forEach(p -> b.addPermission(p));
    return b;
  }

  protected abstract Builder autoToBuilder();

  @AutoValue.Builder
  public abstract static class Builder {
    private final List<Permission.Builder> permissionBuilders;

    protected Builder() {
      permissionBuilders = new ArrayList<>();
    }

    public abstract Builder setName(String name);

    public abstract String getName();

    @CanIgnoreReturnValue
    public Builder modifyPermissions(Consumer<List<Permission.Builder>> modification) {
      modification.accept(permissionBuilders);
      return this;
    }

    @CanIgnoreReturnValue
    public Builder addPermission(Permission.Builder permission) {
      requireNonNull(permission, "permission must be non-null");
      return modifyPermissions(p -> p.add(permission));
    }

    @CanIgnoreReturnValue
    public Builder remove(Permission.Builder permission) {
      requireNonNull(permission, "permission must be non-null");
      return removePermission(permission.getName());
    }

    @CanIgnoreReturnValue
    public Builder removePermission(String name) {
      requireNonNull(name, "name must be non-null");
      return modifyPermissions(
          p -> p.removeIf(permissionBuilder -> name.equalsIgnoreCase(permissionBuilder.getName())));
    }

    @CanIgnoreReturnValue
    public Permission.Builder upsertPermission(String permissionName) {
      requireNonNull(permissionName, "permissionName must be non-null");

      Optional<Permission.Builder> maybePermission =
          permissionBuilders.stream()
              .filter(p -> p.getName().equalsIgnoreCase(permissionName))
              .findAny();
      if (maybePermission.isPresent()) {
        return maybePermission.get();
      }

      Permission.Builder permission = Permission.builder(permissionName);
      modifyPermissions(p -> p.add(permission));
      return permission;
    }

    public AccessSection build() {
      setPermissions(
          permissionBuilders.stream().map(Permission.Builder::build).collect(toImmutableList()));
      if (getPermissions().size()
          > getPermissions().stream()
              .map(Permission::getName)
              .map(String::toLowerCase)
              .distinct()
              .count()) {
        throw new IllegalArgumentException("duplicate permissions: " + getPermissions());
      }
      return autoBuild();
    }

    protected abstract AccessSection autoBuild();

    protected abstract ImmutableList<Permission> getPermissions();

    abstract Builder setPermissions(ImmutableList<Permission> permissions);
  }
}
