package space.nstart.pcp_tgu_service.integration.api

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.time.LocalDateTime
import java.util.TimeZone

class VisibilityPayloadParserTest {

    private val parser = VisibilityPayloadParser(jacksonObjectMapper().findAndRegisterModules())

    private val originalTimeZone: TimeZone = TimeZone.getDefault()

    @AfterEach
    fun restoreTimeZone() {
        TimeZone.setDefault(originalTimeZone)
    }

    @Test
    fun `normalizes zoned instant to UTC naive LocalDateTime`() {
        // Зонированный инстант должен нормализоваться в UTC-naive время независимо от зоны JVM.
        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"))
        val payload = """
            [{
              "noradId": 20,
              "stationId": 102,
              "onStart": {"time": "2026-06-02T14:14:08Z", "elevation": 5.0},
              "onStop":  {"time": "2026-06-02T14:20:00Z", "elevation": 5.0},
              "onMaximum": {"time": "2026-06-02T14:17:00Z", "elevation": 45.0}
            }]
        """.trimIndent()

        val window = parser.parse("20", payload).points.single().observationWindows.single()

        assertEquals(LocalDateTime.parse("2026-06-02T14:14:08"), window.startTime)
        assertEquals(LocalDateTime.parse("2026-06-02T14:20:00"), window.endTime)
    }

    @Test
    fun `truncates window times to microseconds to match persisted timestamp precision`() {
        // Баллистика отдаёт наносекунды; БД (timestamp(6)) хранит микросекунды. Парсер обязан
        // обрезать хвост, иначе проекция и persisted-планы не совпадут по бизнес-ключу.
        val payload = """
            [{
              "noradId": 20,
              "stationId": 102,
              "onStart": {"time": "2026-06-02T14:14:08.548125028Z", "elevation": 5.0},
              "onStop":  {"time": "2026-06-03T14:01:27.615390539Z", "elevation": 5.0},
              "onMaximum": {"time": "2026-06-02T20:00:00Z", "elevation": 45.0}
            }]
        """.trimIndent()

        val points = parser.parse("20", payload)
        val window = points.points.single().observationWindows.single()

        assertEquals(0, window.startTime.nano % 1_000, "наносекундный остаток должен быть обрезан")
        assertEquals(0, window.endTime.nano % 1_000, "наносекундный остаток должен быть обрезан")
        // Микросекундная часть сохраняется как есть.
        assertEquals(548_125_000, window.startTime.nano)
        assertEquals(615_390_000, window.endTime.nano)
        assertEquals(LocalDateTime::class.java, window.startTime.javaClass)
    }
}
