package de.accso.flexinale.common.infrastructure.eventbus;

import de.accso.flexinale.common.api.event.Event;
import de.accso.flexinale.common.shared_kernel.Identifiable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;

final class KafkaProducerAdapter<E extends Event> {
    private static final Logger LOGGER = LoggerFactory.getLogger(KafkaProducerAdapter.class);

    private final KafkaTemplate<String, String> internal_KafkaTemplate;
    private final String kafkaTopicName;

    private final Class<E> eventType;

    public KafkaProducerAdapter(final Class<E> eventType) {
        this.eventType = eventType;

        this.kafkaTopicName = KafkaTopicHelper.createTopicNameFromEventClazz(eventType);
        LOGGER.info("create new %s for Kafka topic %s".formatted(getName(), kafkaTopicName));

        this.internal_KafkaTemplate = new KafkaTemplate<>(
                new DefaultKafkaProducerFactory<>(
                        KafkaConfiguration.producerConfig()
                ));
    }

    public void publish(final Class<E> eventType, final E event) {
        try {
            Identifiable.Id kafkaKey = event.id();
            String kafkaMessage = EventSerializationHelper.serializeEvent2JsonString(event);
            internal_KafkaTemplate
                    .send(kafkaTopicName, kafkaKey.id(), kafkaMessage)
                    .whenComplete((result, ex) -> {
                        if (ex == null) {
                            LOGGER.debug(String.format("message was sent to topic %s " +
                                            "for event type %s, event id %s",
                                    kafkaTopicName,
                                    eventType.getCanonicalName(),
                                    event.id()));
                        } else {
                            LOGGER.error(String.format("Kafka message could not be sent to topic %s " +
                                            "for event type %s, event id %s - error: %s",
                                    kafkaTopicName, eventType.getCanonicalName(),
                                    event.id(),
                                    ex.getMessage()));
                        }
                    });
        }
        catch (Exception ex) {
            LOGGER.error("Kafka message will not sent out for event " + event, ex);
        }
    }

    String getName() {
        return "KafkaProducerAdapter" + "<" + eventType + ">";
    }
}
