@Override
  public CompletableFuture<SendPushNotificationResult> sendNotification(PushNotification pushNotification) {
    Message.Builder builder = Message.builder()
        .setToken(pushNotification.deviceToken())
        .setAndroidConfig(AndroidConfig.builder()
            .setPriority(pushNotification.urgent() ? AndroidConfig.Priority.HIGH : AndroidConfig.Priority.NORMAL)
            .build());

    final String key = switch (pushNotification.notificationType()) {
      case NOTIFICATION -> "newMessageAlert";
      case ATTEMPT_LOGIN_NOTIFICATION_HIGH_PRIORITY -> "attemptLoginContext";
      case CHALLENGE -> "challenge";
      case RATE_LIMIT_CHALLENGE -> "rateLimitChallenge";
    };

    builder.putData(key, pushNotification.data() != null ? pushNotification.data() : "");

    final Timer.Sample sample = Timer.start();

    return GoogleApiUtil.toCompletableFuture(firebaseMessagingClient.sendAsync(builder.build()), executor)
        .whenComplete((ignored, throwable) -> sample.stop(SEND_NOTIFICATION_TIMER))
        .thenApply(ignored -> new SendPushNotificationResult(true, Optional.empty(), false, Optional.empty()))
        .exceptionally(throwable -> {
          if (ExceptionUtils.unwrap(throwable) instanceof final FirebaseMessagingException firebaseMessagingException) {
            final String errorCode;

            if (firebaseMessagingException.getMessagingErrorCode() != null) {
              errorCode = firebaseMessagingException.getMessagingErrorCode().name();
            } else {
              logger.warn("Received an FCM exception with no error code", firebaseMessagingException);
              errorCode = "unknown";
            }

            final boolean unregistered =
                firebaseMessagingException.getMessagingErrorCode() == MessagingErrorCode.UNREGISTERED;

            return new SendPushNotificationResult(false, Optional.of(errorCode), unregistered, Optional.empty());
          } else {
            throw ExceptionUtils.wrap(throwable);
          }
        });
  }
@Test
  void testSendMessageException() {
    final PushNotification pushNotification = new PushNotification("foo", PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, null, null, true);

    final SettableApiFuture<String> sendFuture = SettableApiFuture.create();
    sendFuture.setException(new IOException());

    when(firebaseMessaging.sendAsync(any())).thenReturn(sendFuture);

    final CompletionException completionException =
        assertThrows(CompletionException.class, () -> fcmSender.sendNotification(pushNotification).join());

    verify(firebaseMessaging).sendAsync(any(Message.class));
    assertTrue(completionException.getCause() instanceof IOException);
  }