package space.nstart.pcp.slots_service.service

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.apache.kafka.clients.producer.ProducerRecord
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Test
import org.mockito.ArgumentCaptor
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.springframework.beans.factory.ObjectProvider
import org.springframework.kafka.core.KafkaTemplate
import org.springframework.kafka.support.SendResult
import space.nstart.pcp.pcp_types_lib.dto.ballistics.InitialConditionsDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
import java.nio.charset.StandardCharsets
import java.time.LocalDateTime
import java.util.concurrent.CompletableFuture

class SatelliteIcKafkaPublisherTest {

    private val kafkaTemplate = mock(KafkaTemplate::class.java) as KafkaTemplate<String, Any>
    private val objectMapper = jacksonObjectMapper().findAndRegisterModules()

    @Test
    fun `publisher sends satellite initial conditions to kafka with ICRVPlacedEvent header`() {
        val publisher = SatelliteIcKafkaPublisher(
            kafkaTemplateProvider = SingleObjectProvider(kafkaTemplate),
            objectMapperProvider = SingleObjectProvider(objectMapper),
            topic = "pcp.tle",
            applicationName = "slots-service"
        )
        val recordCaptor = ArgumentCaptor.forClass(ProducerRecord::class.java) as ArgumentCaptor<ProducerRecord<String, Any>>
        `when`(kafkaTemplate.send(recordCaptor.capture())).thenReturn(CompletableFuture.completedFuture(mock(SendResult::class.java) as SendResult<String, Any>))

        publisher.publish(
            SatelliteICDTO(
                satelliteId = 56756L,
                ic = InitialConditionsDTO(
                    orbPoint = OrbPointDTO(
                        time = LocalDateTime.of(2026, 4, 16, 12, 0),
                        revolution = 42L,
                        vx = 1.0,
                        vy = 2.0,
                        vz = 3.0,
                        x = 4.0,
                        y = 5.0,
                        z = 6.0
                    ),
                    sBall = 0.7,
                    f81 = 140.0
                )
            )
        )

        verify(kafkaTemplate).send(recordCaptor.value)
        assertEquals("pcp.tle", recordCaptor.value.topic())
        assertEquals("56756", recordCaptor.value.key())
        val typeHeader = recordCaptor.value.headers().lastHeader("type")
        assertNotNull(typeHeader)
        assertEquals("ICRVPlacedEvent", String(typeHeader.value(), StandardCharsets.UTF_8))
    }

    private class SingleObjectProvider<T : Any>(private val value: T) : ObjectProvider<T> {
        override fun getObject(vararg args: Any?): T = value
        override fun getIfAvailable(): T = value
        override fun getIfUnique(): T = value
        override fun getObject(): T = value
    }
}
