package space.nstart.pcp.slots_service.service

import org.junit.jupiter.api.Test
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEExtensionDTO
import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteSummaryDTO
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

class TleAnalysisServiceTest {

    private val tleMonitoringService: TleMonitoringService = mock()
    private val satelliteCatalogService: SatelliteCatalogService = mock()
    private val service = TleAnalysisService(tleMonitoringService, satelliteCatalogService)

    @Test
    fun `satellites uses TLE satellite id and enriches rows from catalog by norad id`() {
        doReturn(
            listOf(
                SatelliteSummaryDTO(
                    id = 101,
                    noradId = 62138,
                    code = "SAT-62138",
                    name = "Test satellite",
                    typeCode = "EO",
                    scanTle = true
                )
            )
        ).`when`(satelliteCatalogService).allSatellites()
        doReturn(
            listOf(
                TLEExtensionDTO(satelliteId = 62138, revolution = 10, tle = TLEDTO()),
                TLEExtensionDTO(satelliteId = 62138, revolution = 11, tle = TLEDTO())
            )
        ).`when`(tleMonitoringService).allTles()

        val satellites = service.satellites()

        assertEquals(1, satellites.size)
        assertEquals(62138, satellites.single().id)
        assertEquals(101, satellites.single().catalogId)
        assertEquals(62138, satellites.single().noradId)
        assertEquals("SAT-62138", satellites.single().code)
        assertEquals("Test satellite", satellites.single().name)
        assertEquals("EO", satellites.single().typeCode)
        assertEquals(true, satellites.single().scanTle)
        assertEquals(2, satellites.single().tleRecordsCount)
    }

    @Test
    fun `satellites falls back to catalog when TLE records are empty`() {
        doReturn(
            listOf(
                SatelliteSummaryDTO(
                    id = 101,
                    noradId = 62138,
                    code = "SAT-62138",
                    name = "Test satellite"
                )
            )
        ).`when`(satelliteCatalogService).allSatellites()
        doReturn(emptyList<TLEExtensionDTO>()).`when`(tleMonitoringService).allTles()

        val satellites = service.satellites()

        assertEquals(1, satellites.size)
        assertEquals(62138, satellites.single().id)
        assertEquals(101, satellites.single().catalogId)
        assertEquals(62138, satellites.single().noradId)
        assertEquals(0, satellites.single().tleRecordsCount)
    }

    @Test
    fun `analyze satellite uses only requested number of latest TLE records`() {
        doReturn(
            listOf(
                tleRecord(revolution = 1, epoch = "21274.51041667"),
                tleRecord(revolution = 2, epoch = "21275.51041667"),
                tleRecord(revolution = 3, epoch = "21276.51041667")
            )
        ).`when`(tleMonitoringService).satelliteTles(25544)

        val response = service.analyzeSatellite(25544, tleCount = 2)

        assertEquals(2, response.rows.size)
        assertEquals(listOf(2L, 3L), response.rows.map { it.revolution })
    }

    @Test
    fun `analyze satellite reports epoch difference between compared TLE records`() {
        doReturn(
            listOf(
                tleRecord(revolution = 1, epoch = "21275.51041667"),
                tleRecord(revolution = 2, epoch = "21276.01041667")
            )
        ).`when`(tleMonitoringService).satelliteTles(25544)

        val response = service.analyzeSatellite(25544, tleCount = 2)

        assertEquals(2, response.rows.size)
        val currentRow = response.rows[1]
        val discrepancy = assertNotNull(currentRow.discrepancy)
        assertEquals(response.rows[0].epoch, discrepancy.previousEpoch)
        assertTrue(discrepancy.previousEpoch.isBefore(currentRow.epoch))
        assertEquals(12.0, discrepancy.epochDifferenceHours, 0.001)
    }

    private fun tleRecord(revolution: Long, epoch: String = "21275.51041667") =
        TLEExtensionDTO(
            satelliteId = 25544,
            revolution = revolution,
            tle = TLEDTO(
                header = "ISS (ZARYA)",
                first = "1 25544U 98067A   $epoch  .00000282  00000-0  12558-4 0  9993",
                second = "2 25544  51.6435 177.7258 0003783  65.7820  55.4027 15.48915330299929"
            )
        )
}
