package space.nstart.pcp.slots_service.model

import org.junit.jupiter.api.Test
import org.slf4j.LoggerFactory
import space.nstart.pcp.pcp_types_lib.dto.ballistics.RevolutionSign
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.SlotDTO
import space.nstart.pcp.slots_service.model.satellite.AbstractSatellite
import space.nstart.pcp.slots_service.model.satellite.TestSatelliteImpl
import java.time.LocalDateTime
import kotlin.system.measureNanoTime

class ContinuousReqCoverSolverBenchmarkTest {

    private val satellitesById: Map<Long, AbstractSatellite> = mapOf(
        22L to TestSatelliteImpl(id = 22L, maxSurveyDuration = 300, mmi = 10),
        23L to TestSatelliteImpl(id = 23L, maxSurveyDuration = 300, mmi = 10),
        24L to TestSatelliteImpl(id = 24L, maxSurveyDuration = 300, mmi = 10)
    )

    @Test
    fun `benchmark continuous solver on dense strip scenario`() {
        val solver = ContinuousReqCoverSolver(
            logger = LoggerFactory.getLogger("ContinuousReqCoverSolverBenchmark"),
            satellitesById = satellitesById
        )

        val targetWkt = "POLYGON ((0 0, 40 0, 40 2, 0 2, 0 0))"
        val slots = buildScenario()
        repeat(3) { solver.select(targetWkt, slots) }

        val elapsedNanos = measureNanoTime {
            repeat(20) {
                solver.select(targetWkt, slots)
            }
        }
        val elapsedMillis = elapsedNanos / 1_000_000.0
        LoggerFactory.getLogger("ContinuousReqCoverSolverBenchmark")
            .info("continuous benchmark: iterations=20, slots={}, elapsedMs={}", slots.size, "%.3f".format(elapsedMillis))
    }

    private fun buildScenario(): List<SlotDTO> {
        val result = mutableListOf<SlotDTO>()
        val baseTime = LocalDateTime.of(2026, 4, 1, 10, 0)
        var slotNumber = 1L

        for (satelliteId in listOf(22L, 23L, 24L)) {
            for (index in 0 until 60) {
                val left = index * 0.6
                val right = left + 1.4
                val timeStart = index * 18L + satelliteId
                val timeStop = timeStart + 10L
                result += SlotDTO(
                    cycle = 1L,
                    satelliteId = satelliteId,
                    tn = baseTime.plusSeconds(timeStart),
                    tk = baseTime.plusSeconds(timeStop),
                    roll = if (satelliteId == 23L) 5.02 else 5.0,
                    contour = "POLYGON (($left 0, $right 0, $right 2, $left 2, $left 0))",
                    revolution = 100 + index.toLong(),
                    revolutionSign = if (satelliteId == 24L && index % 6 < 2) RevolutionSign.DESC else RevolutionSign.ASC,
                    slotNumber = slotNumber++,
                    latitude = 0.0,
                    longitude = left
                )

                if (index % 5 == 0) {
                    val sliverLeft = left + 1.38
                    val sliverRight = sliverLeft + 0.04
                    result += SlotDTO(
                        cycle = 1L,
                        satelliteId = satelliteId,
                        tn = baseTime.plusSeconds(timeStart + 8L),
                        tk = baseTime.plusSeconds(timeStop + 8L),
                        roll = if (satelliteId == 23L) 5.02 else 5.0,
                        contour = "POLYGON (($sliverLeft 0, $sliverRight 0, $sliverRight 2, $sliverLeft 2, $sliverLeft 0))",
                        revolution = 500 + index.toLong(),
                        revolutionSign = RevolutionSign.ASC,
                        slotNumber = slotNumber++,
                        latitude = 0.0,
                        longitude = sliverLeft
                    )
                }
            }
        }

        return result
    }
}
