// Copyright (C) 2013 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.sshd.commands;

import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

import com.google.common.base.MoreObjects;
import com.google.common.collect.Streams;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.group.GroupResource;
import com.google.gerrit.server.restapi.group.AddMembers;
import com.google.gerrit.server.restapi.group.AddSubgroups;
import com.google.gerrit.server.restapi.group.DeleteMembers;
import com.google.gerrit.server.restapi.group.DeleteSubgroups;
import com.google.gerrit.server.restapi.group.GroupsCollection;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;

@CommandMetaData(
    name = "set-members",
    description = "Modify members of specific group or number of groups")
public class SetMembersCommand extends SshCommand {

  @Option(
      name = "--add",
      aliases = {"-a"},
      metaVar = "USER",
      usage = "users that should be added as group member")
  private List<Account.Id> accountsToAdd = new ArrayList<>();

  @Option(
      name = "--remove",
      aliases = {"-r"},
      metaVar = "USER",
      usage = "users that should be removed from the group")
  private List<Account.Id> accountsToRemove = new ArrayList<>();

  @Option(
      name = "--include",
      aliases = {"-i"},
      metaVar = "GROUP",
      usage = "group that should be included as group member")
  private List<AccountGroup.UUID> groupsToInclude = new ArrayList<>();

  @Option(
      name = "--exclude",
      aliases = {"-e"},
      metaVar = "GROUP",
      usage = "group that should be excluded from the group")
  private List<AccountGroup.UUID> groupsToRemove = new ArrayList<>();

  @Argument(
      index = 0,
      required = true,
      multiValued = true,
      metaVar = "GROUP",
      usage = "groups to modify")
  private List<AccountGroup.UUID> groups = new ArrayList<>();

  @Inject private AddMembers addMembers;

  @Inject private DeleteMembers deleteMembers;

  @Inject private AddSubgroups addSubgroups;

  @Inject private DeleteSubgroups deleteSubgroups;

  @Inject private GroupsCollection groupsCollection;

  @Inject private GroupCache groupCache;

  @Inject private AccountCache accountCache;

  @Override
  protected void run() throws UnloggedFailure, Failure, Exception {
    enableGracefulStop();
    try {
      for (AccountGroup.UUID groupUuid : groups) {
        GroupResource resource =
            groupsCollection.parse(TopLevelResource.INSTANCE, IdString.fromUrl(groupUuid.get()));
        if (!accountsToRemove.isEmpty()) {
          deleteMembers.apply(resource, fromMembers(accountsToRemove));
          reportMembersAction("removed from", resource, accountsToRemove);
        }
        if (!groupsToRemove.isEmpty()) {
          deleteSubgroups.apply(resource, fromGroups(groupsToRemove));
          reportGroupsAction("excluded from", resource, groupsToRemove);
        }
        if (!accountsToAdd.isEmpty()) {
          addMembers.apply(resource, fromMembers(accountsToAdd));
          reportMembersAction("added to", resource, accountsToAdd);
        }
        if (!groupsToInclude.isEmpty()) {
          addSubgroups.apply(resource, fromGroups(groupsToInclude));
          reportGroupsAction("included to", resource, groupsToInclude);
        }
      }
    } catch (RestApiException e) {
      throw die(e.getMessage());
    }
  }

  private void reportMembersAction(
      String action, GroupResource group, List<Account.Id> accountIdList)
      throws UnsupportedEncodingException, IOException {
    String names =
        accountIdList.stream()
            .map(
                accountId -> {
                  Optional<AccountState> accountState = accountCache.get(accountId);
                  if (!accountState.isPresent()) {
                    return "n/a";
                  }
                  return MoreObjects.firstNonNull(
                      accountState.get().account().preferredEmail(), "n/a");
                })
            .collect(joining(", "));
    out.write(
        String.format("Members %s group %s: %s\n", action, group.getName(), names).getBytes(ENC));
  }

  private void reportGroupsAction(
      String action, GroupResource group, List<AccountGroup.UUID> groupUuidList)
      throws UnsupportedEncodingException, IOException {
    String names =
        groupUuidList.stream()
            .map(uuid -> groupCache.get(uuid).map(InternalGroup::getName))
            .flatMap(Streams::stream)
            .collect(joining(", "));
    out.write(
        String.format("Groups %s group %s: %s\n", action, group.getName(), names).getBytes(ENC));
  }

  private AddSubgroups.Input fromGroups(List<AccountGroup.UUID> accounts) {
    return AddSubgroups.Input.fromGroups(accounts.stream().map(Object::toString).collect(toList()));
  }

  private AddMembers.Input fromMembers(List<Account.Id> accounts) {
    return AddMembers.Input.fromMembers(accounts.stream().map(Object::toString).collect(toList()));
  }
}
