package space.nstart.pcp.slots_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.ballistics.SatelliteICDTO
import space.nstart.pcp.pcp_types_lib.message.KafkaMessage
import space.nstart.pcp.pcp_types_lib.message.PcpKafkaEvent
import space.nstart.pcp.slots_service.configuration.CustomErrorException
import java.nio.charset.StandardCharsets

@Component
class SatelliteIcKafkaPublisher(
    kafkaTemplateProvider: ObjectProvider<KafkaTemplate<String, Any>>,
    objectMapperProvider: ObjectProvider<ObjectMapper>,
    @param:Value("\${spring.kafka.template.default-topic:}") private val topic: String,
    @param:Value("\${spring.application.name:slots-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(messagePayload: SatelliteICDTO) {
        val template = kafkaTemplate ?: throw CustomErrorException("Kafka publisher for satellite IC is unavailable")
        if (topic.isBlank()) {
            throw CustomErrorException("Kafka topic for satellite IC publishing is not configured")
        }

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

        val payload = try {
            objectMapper.writeValueAsString(message)
        } catch (exception: JsonProcessingException) {
            throw CustomErrorException("Ошибка сериализации начальных условий КА ${messagePayload.satelliteId}: ${exception.message}")
        }

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

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