// Copyright (C) 2014 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.group;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.gerrit.audit.GroupMemberAuditListener;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.UniversalGroupBackend;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;

import org.slf4j.Logger;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

class DbGroupMemberAuditListener implements GroupMemberAuditListener {
  private static final Logger log = org.slf4j.LoggerFactory
      .getLogger(DbGroupMemberAuditListener.class);

  private final SchemaFactory<ReviewDb> schema;
  private final AccountCache accountCache;
  private final GroupCache groupCache;
  private final UniversalGroupBackend groupBackend;

  @Inject
  public DbGroupMemberAuditListener(SchemaFactory<ReviewDb> schema,
      AccountCache accountCache, GroupCache groupCache,
      UniversalGroupBackend groupBackend) {
    this.schema = schema;
    this.accountCache = accountCache;
    this.groupCache = groupCache;
    this.groupBackend = groupBackend;
  }

  @Override
  public void onAddAccountsToGroup(Account.Id me,
      Collection<AccountGroupMember> added) {
    List<AccountGroupMemberAudit> auditInserts = Lists.newLinkedList();
    for (AccountGroupMember m : added) {
      AccountGroupMemberAudit audit =
          new AccountGroupMemberAudit(m, me, TimeUtil.nowTs());
      auditInserts.add(audit);
    }
    try (ReviewDb db = schema.open()) {
      db.accountGroupMembersAudit().insert(auditInserts);
    } catch (OrmException e) {
      logOrmExceptionForAccounts(
          "Cannot log add accounts to group event performed by user", me,
          added, e);
    }
  }

  @Override
  public void onDeleteAccountsFromGroup(Account.Id me,
      Collection<AccountGroupMember> removed) {
    List<AccountGroupMemberAudit> auditInserts = Lists.newLinkedList();
    List<AccountGroupMemberAudit> auditUpdates = Lists.newLinkedList();
    try (ReviewDb db = schema.open()) {
      for (AccountGroupMember m : removed) {
        AccountGroupMemberAudit audit = null;
        for (AccountGroupMemberAudit a : db.accountGroupMembersAudit()
            .byGroupAccount(m.getAccountGroupId(), m.getAccountId())) {
          if (a.isActive()) {
            audit = a;
            break;
          }
        }

        if (audit != null) {
          audit.removed(me, TimeUtil.nowTs());
          auditUpdates.add(audit);
        } else {
          audit = new AccountGroupMemberAudit(m, me, TimeUtil.nowTs());
          audit.removedLegacy();
          auditInserts.add(audit);
        }
      }
      db.accountGroupMembersAudit().update(auditUpdates);
      db.accountGroupMembersAudit().insert(auditInserts);
    } catch (OrmException e) {
      logOrmExceptionForAccounts(
          "Cannot log delete accounts from group event performed by user", me,
          removed, e);
    }
  }

  @Override
  public void onAddGroupsToGroup(Account.Id me,
      Collection<AccountGroupById> added) {
    List<AccountGroupByIdAud> includesAudit = new ArrayList<>();
    for (AccountGroupById groupInclude : added) {
      AccountGroupByIdAud audit =
          new AccountGroupByIdAud(groupInclude, me, TimeUtil.nowTs());
      includesAudit.add(audit);
    }
    try (ReviewDb db = schema.open()) {
      db.accountGroupByIdAud().insert(includesAudit);
    } catch (OrmException e) {
      logOrmExceptionForGroups(
          "Cannot log add groups to group event performed by user", me, added,
          e);
    }
  }

  @Override
  public void onDeleteGroupsFromGroup(Account.Id me,
      Collection<AccountGroupById> removed) {
    final List<AccountGroupByIdAud> auditUpdates = Lists.newLinkedList();
    try (ReviewDb db = schema.open()) {
      for (final AccountGroupById g : removed) {
        AccountGroupByIdAud audit = null;
        for (AccountGroupByIdAud a : db.accountGroupByIdAud()
            .byGroupInclude(g.getGroupId(), g.getIncludeUUID())) {
          if (a.isActive()) {
            audit = a;
            break;
          }
        }

        if (audit != null) {
          audit.removed(me, TimeUtil.nowTs());
          auditUpdates.add(audit);
        }
      }
      db.accountGroupByIdAud().update(auditUpdates);
    } catch (OrmException e) {
      logOrmExceptionForGroups(
          "Cannot log delete groups from group event performed by user", me,
          removed, e);
    }
  }

  private void logOrmExceptionForAccounts(String header, Account.Id me,
      Collection<AccountGroupMember> values, OrmException e) {
    List<String> descriptions = new ArrayList<>();
    for (AccountGroupMember m : values) {
      Account.Id accountId = m.getAccountId();
      String userName = accountCache.get(accountId).getUserName();
      AccountGroup.Id groupId = m.getAccountGroupId();
      String groupName = groupCache.get(groupId).getName();

      descriptions.add(MessageFormat.format("account {0}/{1}, group {2}/{3}",
          accountId, userName, groupId, groupName));
    }
    logOrmException(header, me, descriptions, e);
  }

  private void logOrmExceptionForGroups(String header, Account.Id me,
      Collection<AccountGroupById> values, OrmException e) {
    List<String> descriptions = new ArrayList<>();
    for (AccountGroupById m : values) {
      AccountGroup.UUID groupUuid = m.getIncludeUUID();
      String groupName = groupBackend.get(groupUuid).getName();
      AccountGroup.Id targetGroupId = m.getGroupId();
      String targetGroupName = groupCache.get(targetGroupId).getName();

      descriptions.add(MessageFormat.format("group {0}/{1}, group {2}/{3}",
          groupUuid, groupName, targetGroupId, targetGroupName));
    }
    logOrmException(header, me, descriptions, e);
  }

  private void logOrmException(String header, Account.Id me,
      Iterable<?> values, OrmException e) {
    StringBuilder message = new StringBuilder(header);
    message.append(" ");
    message.append(me);
    message.append("/");
    message.append(accountCache.get(me).getUserName());
    message.append(": ");
    message.append(Joiner.on("; ").join(values));
    log.error(message.toString(), e);
  }
}
