Mono<NotificationContent> inferenceTemplate(Reason reason, Subscriber subscriber,
        Locale locale) {
        var reasonTypeName = reason.getSpec().getReasonType();
        return getReasonType(reasonTypeName)
            .flatMap(reasonType -> notificationTemplateSelector.select(reasonTypeName, locale)
                .flatMap(template -> {
                    final var templateContent = template.getSpec().getTemplate();
                    var model = toReasonAttributes(reason);
                    var subscriberInfo = new HashMap<>();
                    if (subscriber.isAnonymous()) {
                        subscriberInfo.put("displayName", subscriber.getEmail().orElseThrow());
                    } else {
                        subscriberInfo.put("displayName", "@" + subscriber.username());
                    }
                    subscriberInfo.put("id", subscriber.name());
                    model.put("subscriber", subscriberInfo);

                    var unsubscriptionMono = getUnsubscribeUrl(subscriber.subscriptionName())
                        .doOnNext(url -> model.put("unsubscribeUrl", url));

                    var builder = NotificationContent.builder()
                        .reasonType(reasonType)
                        .reasonAttributes(model);

                    var titleMono = notificationTemplateRender
                        .render(templateContent.getTitle(), model)
                        .doOnNext(builder::title);

                    var rawBodyMono = notificationTemplateRender
                        .render(templateContent.getRawBody(), model)
                        .doOnNext(builder::rawBody);

                    var htmlBodyMono = notificationTemplateRender
                        .render(templateContent.getHtmlBody(), model)
                        .doOnNext(builder::htmlBody);
                    return Mono.when(unsubscriptionMono, titleMono, rawBodyMono, htmlBodyMono)
                        .then(Mono.fromSupplier(builder::build));
                })
            );
    }
@Test
    public void testInferenceTemplate() {
        final var spyNotificationCenter = spy(notificationCenter);

        final var reasonType = mock(ReasonType.class);

        var reason = new Reason();
        reason.setMetadata(new Metadata());
        reason.getMetadata().setName("reason-a");
        reason.setSpec(new Reason.Spec());
        reason.getSpec().setReasonType("new-reply-on-comment");

        var reasonTypeName = reason.getSpec().getReasonType();

        doReturn(Mono.just(reasonType))
            .when(spyNotificationCenter).getReasonType(eq(reasonTypeName));
        doReturn(Mono.just("fake-unsubscribe-url"))
            .when(spyNotificationCenter).getUnsubscribeUrl(anyString());

        final var locale = Locale.CHINESE;

        var template = new NotificationTemplate();
        template.setMetadata(new Metadata());
        template.getMetadata().setName("notification-template-a");
        template.setSpec(new NotificationTemplate.Spec());
        template.getSpec().setTemplate(new NotificationTemplate.Template());
        template.getSpec().getTemplate().setRawBody("body");
        template.getSpec().getTemplate().setHtmlBody("html-body");
        template.getSpec().getTemplate().setTitle("title");
        template.getSpec().setReasonSelector(new NotificationTemplate.ReasonSelector());
        template.getSpec().getReasonSelector().setReasonType(reasonTypeName);
        template.getSpec().getReasonSelector().setLanguage(locale.getLanguage());

        when(notificationTemplateRender.render(anyString(), any()))
            .thenReturn(Mono.empty());
        when(notificationTemplateSelector.select(eq(reasonTypeName), any()))
            .thenReturn(Mono.just(template));

        var subscriber = new Subscriber(UserIdentity.anonymousWithEmail("A"), "fake-name");

        spyNotificationCenter.inferenceTemplate(reason, subscriber, locale).block();

        verify(spyNotificationCenter).getReasonType(eq(reasonTypeName));
        verify(notificationTemplateSelector).select(eq(reasonTypeName), any());
    }