content: package bankservice.projection.clientaccounts;
  
  import static java.util.Collections.emptyMap;
  
  import com.google.common.collect.ImmutableList;
  import java.math.BigDecimal;
  import java.util.AbstractMap;
  import java.util.List;
  import java.util.Map;
  import java.util.UUID;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.stream.Collectors;
  import java.util.stream.Stream;
  
  public class InMemoryAccountsRepository implements AccountsRepository {
  
    private final Map<UUID, Map<UUID, AccountProjection>> clientAccounts = new ConcurrentHashMap<>();
    private final Map<UUID, UUID> accountClientIndex = new ConcurrentHashMap<>();
  
    @Override
    public void save(AccountProjection accountProjection) {
      clientAccounts.merge(
          accountProjection.getClientId(),
          newAccountsMap(accountProjection),
          (oldValue, value) -> {
            oldValue.putAll(value);
            return oldValue;
          }
      );
      accountClientIndex.put(accountProjection.getAccountId(), accountProjection.getClientId());
    }
  
    @Override
    public void updateBalance(UUID accountId, BigDecimal balance, int version) {
      UUID clientId = accountClientIndex.get(accountId);
      clientAccounts.get(clientId).merge(
          accountId,
          new AccountProjection(accountId, clientId, balance, version),
          (oldValue, value) -> value.getVersion() > oldValue.getVersion() ? value : oldValue);
    }
  
    @Override
    public List<AccountProjection> getAccounts(UUID clientId) {
      Map<UUID, AccountProjection> accounts = clientAccounts.getOrDefault(clientId, emptyMap());
      return ImmutableList.copyOf(accounts.values());
    }
  
    private Map<UUID, AccountProjection> newAccountsMap(AccountProjection accountProjection) {
      return Stream.of(
          new AbstractMap.SimpleEntry<>(accountProjection.getAccountId(), accountProjection))
          .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }
  }
  