class BatchSecretDeliveryResource {

  @Timed
  @ExceptionMetered
  @POST
  @Consumes(APPLICATION_JSON)
  public List<SecretDeliveryResponse> getBatchSecret(@Auth Client client, @Valid BatchSecretRequest request) {


    List<SanitizedSecret> clientAccessibleSecrets = aclDAO.getBatchSanitizedSecretsFor(client, request.secrets());
    List<Secret> existingSecrets = secretController.getSecretsByName(request.secrets());

    boolean clientExists = clientDAO.getClientByName(client.getName()).isPresent();

    List<String> forbiddenSecrets = new ArrayList<>();

    // The request fails whenever a single secret is requested that is not accessible
    // The client is responsible for only requesting secrets they have permission for
    for (String secretname : request.secrets()) {
      boolean secretExists = existingSecrets.stream().anyMatch(s -> s.getName().equals(secretname));
      boolean secretAccessible = clientAccessibleSecrets.stream().anyMatch(s -> s.name().equals(secretname));

      if (!(clientExists && secretExists)) {
        logger.warn("Client {} or secret {} does not exist (client exists={}, secret exists={})", client.getName(), secretname, clientExists, secretExists);
        throw new NotFoundException();
      }
      if (!secretAccessible) {
        // at this point we know the client and secret both exist
        forbiddenSecrets.add(secretname);
      }
    }

    // If *any* of the secrets is forbidden
    if (!forbiddenSecrets.isEmpty()) {
      throw new ForbiddenException(format("Access denied: %s to secret(s) '%s'", client.getName(), forbiddenSecrets));
    }

    logger.info("Client {} granted access to {}.", client.getName(), clientAccessibleSecrets.stream().map(s -> s.name()).collect(toList()));
    try {
      // This is only possible if all secrets are both existing AND accessible to the client
      return existingSecrets.stream()
              .map(SecretDeliveryResponse::fromSecret)
              .collect(toList());
    } catch (IllegalArgumentException e) {
      logger.error(format("Failed creating batch response for secrets %s", existingSecrets.stream().map(s -> s.getName()).collect(toList())), e);
      throw new InternalServerErrorException();
    }
  }

  @Inject public  BatchSecretDeliveryResource(@Readonly SecretController secretController,
                                     AclDAOFactory aclDAOFactory, ClientDAOFactory clientDAOFactory);
  @VisibleForTesting  BatchSecretDeliveryResource(SecretController secretController, AclDAO aclDAO,
                              ClientDAO clientDAO);

}