package space.nstart.pcp.slots_service.repository

import org.junit.jupiter.api.Test
import org.mockito.Mockito.mock
import org.mockito.Mockito.verifyNoInteractions
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.test.util.ReflectionTestUtils
import java.sql.Timestamp
import java.time.LocalDateTime
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class SlotRepositoryImplTest {

    @Test
    fun `findTargetSlotRows returns empty result without hitting jdbc for empty request batch`() {
        val jdbcTemplate = mock(JdbcTemplate::class.java)
        val repository = SlotRepositoryImpl(jdbcTemplate)

        val result = repository.findTargetSlotRows(emptyList(), chunkSize = 256)

        assertTrue(result.isEmpty())
        verifyNoInteractions(jdbcTemplate)
    }

    @Test
    fun `batch spatial fetch sql filters by satellite time bbox and exact geometry without giant in`() {
        val repository = SlotRepositoryImpl(mock(JdbcTemplate::class.java))

        val sql = ReflectionTestUtils.invokeMethod<String>(repository, "buildBatchSpatialFetchSql", 2)
        val params = ReflectionTestUtils.invokeMethod<Array<Any>>(
            repository,
            "buildBatchSpatialFetchParams",
            listOf(
                BatchCoverageSearchRequest(
                    targetId = 1L,
                    satelliteId = 22L,
                    windowStart = LocalDateTime.of(2026, 4, 1, 10, 0),
                    windowStop = LocalDateTime.of(2026, 4, 1, 12, 0),
                    polygonWkt = "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"
                ),
                BatchCoverageSearchRequest(
                    targetId = 2L,
                    satelliteId = 33L,
                    windowStart = LocalDateTime.of(2026, 4, 2, 10, 0),
                    windowStop = LocalDateTime.of(2026, 4, 2, 12, 0),
                    polygonWkt = "POLYGON ((1 1, 2 1, 2 2, 1 2, 1 1))"
                )
            )
        )

        requireNotNull(sql)
        requireNotNull(params)
        assertTrue(sql.contains("slot.satellite_id = search.satellite_id"))
        assertTrue(sql.contains("slot.tn >= search.window_start"))
        assertTrue(sql.contains("slot.tk <= search.window_stop"))
        assertTrue(sql.contains("slot.contour_geom && search.search_geom"))
        assertTrue(sql.contains("st_intersects(search.search_geom, slot.contour_geom)"))
        assertFalse(sql.contains("slot.satellite_id in"))
        assertFalse(sql.contains("slot_id in"))
        assertEquals(10, params.size)
        assertEquals(Timestamp.valueOf(LocalDateTime.of(2026, 4, 1, 10, 0)), params[2])
        assertEquals(Timestamp.valueOf(LocalDateTime.of(2026, 4, 1, 12, 0)), params[3])
        assertEquals(Timestamp.valueOf(LocalDateTime.of(2026, 4, 2, 10, 0)), params[7])
        assertEquals(Timestamp.valueOf(LocalDateTime.of(2026, 4, 2, 12, 0)), params[8])
    }
}
