package space.nstart.pcp.pcp_coverage_scheme_service.controller

import org.junit.jupiter.api.Test
import org.mockito.Mockito.doReturn
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.server.LocalServerPort
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.web.reactive.function.client.WebClient
import space.nstart.pcp.pcp_coverage_scheme_service.service.CoverageSchemeCalculationService
import space.nstart.pcp.pcp_types_lib.dto.ballistics.RevolutionSign
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SquareViewParamDTO
import space.nstart.pcp.pcp_types_lib.dto.coverage.CoverageObservationDTO
import space.nstart.pcp.pcp_types_lib.dto.coverage.CoverageSchemeCalculateRequestDTO
import space.nstart.pcp.pcp_types_lib.dto.coverage.CoverageSchemeResponseDTO
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.SurveySlotDTO
import tools.jackson.databind.ObjectMapper
import java.time.LocalDateTime
import kotlin.test.assertEquals

@SpringBootTest(
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    properties = [
        "spring.boot.admin.client.enabled=false",
        "spring.cloud.config.enabled=false",
        "spring.cloud.config.import-check.enabled=false",
        "spring.config.import="
    ]
)
class CoverageSchemeControllerTest {

    @LocalServerPort
    private var port: Int = 0

    @MockitoBean
    private lateinit var coverageSchemeCalculationService: CoverageSchemeCalculationService

    private val objectMapper = ObjectMapper()

    @Test
    fun `calculate endpoint returns observations with contours`() {
        doReturn(
            CoverageSchemeResponseDTO(
                targetPolygonWkt = "POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))",
                observations = listOf(
                    CoverageObservationDTO(
                        observation = SquareViewParamDTO(
                            noradId = 11L,
                            timeBegin = LocalDateTime.of(2026, 4, 14, 10, 0),
                            timeEnd = LocalDateTime.of(2026, 4, 14, 10, 5),
                            revSignBegin = RevolutionSign.ASC,
                            revSignEnd = RevolutionSign.ASC,
                            gammaMin = 0.0,
                            gammaMax = 10.0
                        ),
                        intersectionContourWkts = listOf("POLYGON ((0.5 0, 1.5 0, 1.5 2, 0.5 2, 0.5 0))")
                    )
                ),
                coverageScheme = listOf(
                    SurveySlotDTO(
                        satelliteId = 11L,
                        tn = LocalDateTime.of(2026, 4, 14, 10, 0),
                        tk = LocalDateTime.of(2026, 4, 14, 10, 5),
                        roll = 5.0,
                        contour = "POLYGON ((0.5 0, 1.5 0, 1.5 2, 0.5 2, 0.5 0))",
                        revolutionSign = RevolutionSign.ASC
                    )
                )
            )
        )
            .`when`(coverageSchemeCalculationService)
            .calculate(org.mockito.ArgumentMatchers.any(CoverageSchemeCalculateRequestDTO::class.java) ?: CoverageSchemeCalculateRequestDTO())

        val actual = WebClient.create("http://localhost:$port")
            .post()
            .uri("/api/coverage-schemes/calculate")
            .bodyValue(
                CoverageSchemeCalculateRequestDTO(
                    polygonWkt = "POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))",
                    satelliteIds = listOf(11L),
                    timeStart = LocalDateTime.of(2026, 4, 14, 10, 0),
                    timeEnd = LocalDateTime.of(2026, 4, 14, 11, 0)
                )
            )
            .retrieve()
            .bodyToMono(String::class.java)
            .map(objectMapper::readTree)
            .block()!!

        assertEquals(1, actual["observations"].size())
        assertEquals(1, actual["coverageScheme"].size())
        assertEquals(11L, actual["observations"][0]["observation"]["noradId"].asLong())
        assertEquals(
            "POLYGON ((0.5 0, 1.5 0, 1.5 2, 0.5 2, 0.5 0))",
            actual["observations"][0]["intersectionContourWkts"][0].textValue()
        )
    }
}
