package space.nstart.pcp.pcp_satellite_catalog_service.service

import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.apache.kafka.clients.producer.ProducerRecord
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.ObjectProvider
import org.springframework.beans.factory.annotation.Value
import org.springframework.kafka.core.KafkaTemplate
import org.springframework.stereotype.Component
import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteDeletedEventDTO
import space.nstart.pcp.pcp_types_lib.message.KafkaMessage
import space.nstart.pcp.pcp_types_lib.message.PcpKafkaEvent
import java.nio.charset.StandardCharsets

@Component
class SatelliteDeletedKafkaPublisher(
    kafkaTemplateProvider: ObjectProvider<KafkaTemplate<String, Any>>,
    objectMapperProvider: ObjectProvider<ObjectMapper>,
    @param:Value("\${app.kafka.topics.satellites:pcp.satellites}") private val topic: String,
    @param:Value("\${spring.application.name:pcp-satellite-catalog-service}") private val applicationName: String
) {

    private val logger = LoggerFactory.getLogger(this::class.java)
    private val kafkaTemplate = kafkaTemplateProvider.ifAvailable
    private val objectMapper = objectMapperProvider.ifAvailable ?: jacksonObjectMapper().findAndRegisterModules()

    fun publish(event: SatelliteDeletedEventDTO) {
        val template = kafkaTemplate
        if (template == null || topic.isBlank()) {
            logger.warn(
                "SatelliteDeletedEvent was not published because Kafka is not configured: satelliteId={}, noradId={}, topic={}",
                event.satelliteId,
                event.noradId,
                topic
            )
            return
        }

        val message = KafkaMessage(
            type = PcpKafkaEvent.SatelliteDeletedEvent,
            data = event
        ).apply {
            source = applicationName
        }

        val payload = try {
            objectMapper.writeValueAsString(message)
        } catch (exception: JsonProcessingException) {
            throw IllegalStateException("Failed to serialize SatelliteDeletedEvent for satellite ${event.satelliteId}", exception)
        }

        val record = ProducerRecord<String, Any>(topic, event.satelliteId.toString(), payload)
        record.headers().add(TYPE_HEADER, PcpKafkaEvent.SatelliteDeletedEvent.name.toByteArray(StandardCharsets.UTF_8))
        template.send(record)
        logger.info(
            "Published SatelliteDeletedEvent: satelliteId={}, noradId={}, topic={}, eventType={}",
            event.satelliteId,
            event.noradId,
            topic,
            PcpKafkaEvent.SatelliteDeletedEvent
        )
    }

    companion object {
        private const val TYPE_HEADER = "type"
    }
}
