package space.nstart.pcp.pcp_satellites_service.service

import com.sun.net.httpserver.HttpServer
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.springframework.beans.factory.ObjectProvider
import org.springframework.test.util.ReflectionTestUtils
import org.springframework.web.reactive.function.client.WebClient
import space.nstart.pcp.pcp_types_lib.dto.requests.CoverageCalculationSource
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.SlotCoverageTargetDTO
import java.net.InetSocketAddress
import java.time.LocalDateTime
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class CoverageSchemeCalculationClientTest {

    private var server: HttpServer? = null

    @AfterEach
    fun tearDown() {
        server?.stop(0)
    }

    @Test
    fun `coverageModes calls coverage scheme service and maps response to slot model`() {
        var requestBody = ""
        server = HttpServer.create(InetSocketAddress(0), 0).apply {
            createContext("/api/coverage-schemes/calculate") { exchange ->
                requestBody = exchange.requestBody.bufferedReader().readText()
                val responseBody = """
                    {
                      "targetPolygonWkt": "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))",
                      "observations": [],
                      "coverageScheme": [
                        {
                          "satelliteId": 22,
                          "tn": "2026-03-26T10:05:00",
                          "tk": "2026-03-26T10:15:00",
                          "roll": 8.5,
                          "contour": "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))",
                          "revolution": 501,
                          "revolutionSign": "ASC",
                          "slotIds": [],
                          "latitude": 10.0,
                          "longitude": 20.0
                        }
                      ]
                    }
                """.trimIndent()
                exchange.responseHeaders.add("Content-Type", "application/json")
                exchange.sendResponseHeaders(200, responseBody.toByteArray().size.toLong())
                exchange.responseBody.use { it.write(responseBody.toByteArray()) }
            }
            start()
        }

        val builderProvider = mock(ObjectProvider::class.java) as ObjectProvider<WebClient.Builder>
        `when`(builderProvider.ifAvailable).thenReturn(WebClient.builder())

        val client = CoverageSchemeCalculationClient(builderProvider)
        ReflectionTestUtils.setField(client, "url", "http://localhost:${server!!.address.port}")

        val result = client.coverageModes(
            targets = listOf(SlotCoverageTargetDTO(targetId = 101L, wkt = "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))")),
            intervalStart = LocalDateTime.of(2026, 3, 26, 10, 0),
            intervalEnd = LocalDateTime.of(2026, 3, 26, 12, 0),
            satelliteIds = listOf(22L),
            occupiedIntervals = emptyList(),
            sun = null
        )

        val slot = result.getValue(101L).single()
        assertEquals(CoverageCalculationSource.COVERAGE_SCHEME, client.source)
        assertTrue(requestBody.contains("\"polygonWkt\":\"POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))\""))
        assertTrue(requestBody.contains("\"satelliteIds\":[22]"))
        assertEquals(22L, slot.satelliteId)
        assertEquals(8.5, slot.roll)
        assertEquals(501L, slot.revolution)
        assertEquals(10.0, slot.latitude)
        assertEquals(20.0, slot.longitude)
    }
}
