package space.nstart.pcp.slots_service.rest

import org.junit.jupiter.api.Test
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.verify
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_types_lib.dto.ballistics.RevolutionSign
import space.nstart.pcp.slots_service.czml.CZMLColor
import space.nstart.pcp.slots_service.czml.CZMLEntity
import space.nstart.pcp.slots_service.czml.CZMLMaterial
import space.nstart.pcp.slots_service.czml.CZMLPolygon
import space.nstart.pcp.slots_service.czml.CZMLPosition
import space.nstart.pcp.slots_service.service.CoverageSchemeModeRowDTO
import space.nstart.pcp.slots_service.service.CoverageSchemeService
import space.nstart.pcp.slots_service.service.CoverageSchemeUiResponseDTO
import space.nstart.pcp.slots_service.service.EarthService
import space.nstart.pcp.slots_service.service.ComplexMissionService
import space.nstart.pcp.slots_service.service.SlotService
import space.nstart.pcp.slots_service.service.StationService
import tools.jackson.databind.ObjectMapper
import java.time.LocalDateTime
import kotlin.test.assertEquals
import kotlin.test.assertNotNull

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

    @LocalServerPort
    private var port: Int = 0

    @MockitoBean
    private lateinit var earthService: EarthService

    @MockitoBean
    private lateinit var complexMissionService: ComplexMissionService

    @MockitoBean
    private lateinit var stationService: StationService

    @MockitoBean
    private lateinit var slotService: SlotService

    @MockitoBean
    private lateinit var coverageSchemeService: CoverageSchemeService

    private val objectMapper = ObjectMapper()

    @Test
    fun `request coverage scheme endpoint returns map and table payload`() {
        val requestId = "req-scheme"
        val timeStart = LocalDateTime.of(2026, 4, 14, 10, 0)
        val timeStop = LocalDateTime.of(2026, 4, 14, 12, 0)
        val satellites = listOf(11L, 22L)
        val rollStepDegrees = 2.5
        val minimumTechnologyOverlap = 0.1
        val strictContinuousCoverage = false
        val allowPartialCoverage = true
        val orientationToleranceDegrees = 7.5
        val includeDebugInfo = false

        doReturn(
            CoverageSchemeUiResponseDTO(
                cov = listOf(
                    CZMLEntity("document", "req_cov_scheme_$requestId", "1.1"),
                    CZMLEntity(
                        id = "coverage_mode_${requestId}_11_1",
                        name = "Режим схемы покрытия",
                        polygon = CZMLPolygon(
                            positions = CZMLPosition(cartographicDegrees = listOf(30.0, 10.0, 0.0, 40.0, 40.0, 0.0, 20.0, 40.0, 0.0, 30.0, 10.0, 0.0)),
                            outlineColor = CZMLColor(12, 34, 56, 255),
                            material = CZMLMaterial(12, 34, 56, 150)
                        )
                    )
                ),
                slots = listOf(
                    CoverageSchemeModeRowDTO(
                        entityId = "coverage_mode_${requestId}_11_1",
                        sequence = 1,
                        satelliteId = 11L,
                        tn = timeStart,
                        tk = timeStart.plusMinutes(5),
                        roll = 12.5,
                        revolutionSign = RevolutionSign.ASC,
                        contour = "POLYGON((30 10, 40 40, 20 40, 30 10))",
                        selectionReason = "seed from WEST"
                    )
                )
            )
        ).`when`(coverageSchemeService).requestCoverageScheme(
            requestId,
            timeStart,
            timeStop,
            satellites,
            rollStepDegrees,
            minimumTechnologyOverlap,
            strictContinuousCoverage,
            allowPartialCoverage,
            orientationToleranceDegrees,
            includeDebugInfo
        )

        val actual = WebClient.create("http://localhost:$port")
            .post()
            .uri(
                "/requests/req-with-coverage-scheme/$requestId" +
                    "?tn=2026-04-14T10:00:00" +
                    "&tk=2026-04-14T12:00:00" +
                    "&rollStepDegrees=2.5" +
                    "&minimumTechnologyOverlap=0.1" +
                    "&strictContinuousCoverage=false" +
                    "&allowPartialCoverage=true" +
                    "&orientationToleranceDegrees=7.5" +
                    "&includeDebugInfo=false" +
                    "&satellites=11" +
                    "&satellites=22"
            )
            .retrieve()
            .bodyToMono(String::class.java)
            .map(objectMapper::readTree)
            .block()!!

        assertEquals(2, actual["cov"].size())
        assertEquals(1, actual["slots"].size())
        assertEquals(1, actual["slots"][0]["sequence"].asInt())
        assertEquals(11L, actual["slots"][0]["satelliteId"].asLong())
        assertNotNull(actual["slots"][0]["entityId"])
        verify(coverageSchemeService).requestCoverageScheme(
            requestId,
            timeStart,
            timeStop,
            satellites,
            rollStepDegrees,
            minimumTechnologyOverlap,
            strictContinuousCoverage,
            allowPartialCoverage,
            orientationToleranceDegrees,
            includeDebugInfo
        )
    }
}
