package space.nstart.pcp.slots_service.service

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.ObjectProvider
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.kafka.annotation.KafkaListener
import org.springframework.stereotype.Component
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.BookedSlotsStatusChangedEvent
import space.nstart.pcp.pcp_types_lib.message.PcpKafkaEvent

@ConditionalOnProperty(name = ["spring.kafka.bootstrap-servers"], matchIfMissing = false)
@Component
class BookedSlotsKafkaListener(
    objectMapperProvider: ObjectProvider<ObjectMapper>,
    private val bookedSlotStatusService: BookedSlotStatusUpdater
) {

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

    @KafkaListener(
        topics = ["\${app.kafka.topics.booked-slots}"],
        groupId = "\${spring.kafka.consumer.group-id}-booked-slots"
    )
    fun consume(message: String) {
        try {
            val payload = objectMapper.readTree(message)
            val eventType = payload.path("type").asText()
            if (eventType != PcpKafkaEvent.BookedSlotsStatusChangedEvent.name) {
                logger.debug("Ignoring Kafka message with unsupported type {}", eventType)
                return
            }

            val event = readEvent(payload)
            bookedSlotStatusService.updateBookedSlotsStatus(
                bookedSlotIds = event.bookedSlotIds,
                targetStatus = event.status,
                context = "kafka:${event.sourceService}:${event.missionId ?: "-"}:${event.modeId ?: "-"}"
            )
        } catch (exception: Exception) {
            logger.error("Failed to process booked slots Kafka event", exception)
            throw exception
        }
    }

    private fun readEvent(payload: JsonNode): BookedSlotsStatusChangedEvent =
        objectMapper.treeToValue(payload.path("data"), BookedSlotsStatusChangedEvent::class.java)
}
