package space.nstart.pcp.complan

import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestMapping
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

class ComPlanControllerTest {

    @Test
    fun `exposes calculation run endpoints`() {
        val mappedMethods = ComPlanController::class.java.declaredMethods
            .filter { method ->
                listOf(
                    GetMapping::class.java,
                    PostMapping::class.java,
                    PutMapping::class.java,
                    PatchMapping::class.java,
                    DeleteMapping::class.java,
                    RequestMapping::class.java
                ).any { annotation -> method.isAnnotationPresent(annotation) }
            }
            .map { it.name }
            .sorted()

        assertEquals(
            listOf(
                "calcPlan",
                "debugGreedyMath",
                "debugObservationParameters",
                "getCalculation",
                "getCalculationIntervals",
                "getCalculationResult",
                "getCalculationRoutes",
                "getCalculations",
                "testCalcMars"
            ),
            mappedMethods
        )
    }

    @Test
    fun `calcPlan is exposed as POST endpoint`() {
        val calcPlanMethod = ComPlanController::class.java.getDeclaredMethod(
            "calcPlan",
            space.nstart.pcp.complan.types.ComplexPlanCalculationRequestDTO::class.java
        )

        assertNotNull(calcPlanMethod.getAnnotation(PostMapping::class.java))
        assertNull(calcPlanMethod.getAnnotation(GetMapping::class.java))
    }

    @Test
    fun `observation parameters debug endpoint is exposed as POST endpoint`() {
        val debugMethod = ComPlanController::class.java.getDeclaredMethod(
            "debugObservationParameters",
            space.nstart.pcp.complan.types.ObservationParametersDebugRequestDTO::class.java
        )

        assertNotNull(debugMethod.getAnnotation(PostMapping::class.java))
        assertNull(debugMethod.getAnnotation(GetMapping::class.java))
    }

    @Test
    fun `greedy math debug endpoint is exposed as POST endpoint`() {
        val debugMethod = ComPlanController::class.java.getDeclaredMethod(
            "debugGreedyMath",
            space.nstart.pcp.complan.types.GreedyMathDebugRequestDTO::class.java
        )

        assertNotNull(debugMethod.getAnnotation(PostMapping::class.java))
        assertNull(debugMethod.getAnnotation(GetMapping::class.java))
    }

    @Test
    fun `test calc mars debug endpoint is exposed as POST endpoint`() {
        val debugMethod = ComPlanController::class.java.getDeclaredMethod(
            "testCalcMars",
            space.nstart.pcp.complan.types.TestCalcMarsDebugRequestDTO::class.java
        )

        assertNotNull(debugMethod.getAnnotation(PostMapping::class.java))
        assertNull(debugMethod.getAnnotation(GetMapping::class.java))
    }

    @Test
    fun `calculation status and result are exposed as GET endpoints`() {
        val statusMethod = ComPlanController::class.java.getDeclaredMethod(
            "getCalculation",
            java.util.UUID::class.java
        )
        val resultMethod = ComPlanController::class.java.getDeclaredMethod(
            "getCalculationResult",
            java.util.UUID::class.java
        )
        val routesMethod = ComPlanController::class.java.getDeclaredMethod(
            "getCalculationRoutes",
            java.util.UUID::class.java,
            Int::class.java,
            Int::class.java
        )
        val intervalsMethod = ComPlanController::class.java.getDeclaredMethod(
            "getCalculationIntervals",
            java.util.UUID::class.java,
            Int::class.java,
            Int::class.java
        )
        val runsMethod = ComPlanController::class.java.getDeclaredMethod(
            "getCalculations",
            space.nstart.pcp.complan.types.DynamicPlanRunStatus::class.java,
            Int::class.java,
            Int::class.java
        )

        assertNotNull(statusMethod.getAnnotation(GetMapping::class.java))
        assertNotNull(resultMethod.getAnnotation(GetMapping::class.java))
        assertNotNull(routesMethod.getAnnotation(GetMapping::class.java))
        assertNotNull(intervalsMethod.getAnnotation(GetMapping::class.java))
        assertNotNull(runsMethod.getAnnotation(GetMapping::class.java))
        assertNull(statusMethod.getAnnotation(PostMapping::class.java))
        assertNull(resultMethod.getAnnotation(PostMapping::class.java))
        assertNull(routesMethod.getAnnotation(PostMapping::class.java))
        assertNull(intervalsMethod.getAnnotation(PostMapping::class.java))
        assertNull(runsMethod.getAnnotation(PostMapping::class.java))
    }
}
