package space.nstart.pcp_tgu_service.controller

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import space.nstart.pcp_tgu_service.domain.PlanDecision
import space.nstart.pcp_tgu_service.dto.NsiPlatformDto
import space.nstart.pcp_tgu_service.dto.PlanDecisionMessage
import space.nstart.pcp_tgu_service.dto.PlanExecutionFeedbackMessage
import space.nstart.pcp_tgu_service.dto.PlanResponse
import space.nstart.pcp_tgu_service.integration.api.ExternalPointsClient
import space.nstart.pcp_tgu_service.service.HandlePlanDecisionUseCase
import space.nstart.pcp_tgu_service.service.PlanProjectionService
import space.nstart.pcp_tgu_service.service.PlanQueryService
import space.nstart.pcp_tgu_service.service.PlatformService
import space.nstart.pcp_tgu_service.service.TestPlanDecisionService
import space.nstart.pcp_tgu_service.service.VisibilityRefreshJobService
import java.time.LocalDateTime
import java.util.UUID

/**
 * Test-only controller for manual TGU operations. Disabled by default.
 */
@ConditionalOnProperty(prefix = "tgu.test-controller", name = ["enabled"], havingValue = "true")
@RestController
@RequestMapping("/test/tgu")
class TestTguController(
    private val visibilityRefreshJobService: VisibilityRefreshJobService,
    private val planProjectionService: PlanProjectionService,
    private val handlePlanDecisionUseCase: HandlePlanDecisionUseCase,
    private val testPlanDecisionService: TestPlanDecisionService,
    private val externalPointsClient: ExternalPointsClient,
    private val platformService: PlatformService,
    private val planQueryService: PlanQueryService
) {
    /** Ставит refresh job для КА. */
    @PostMapping("/spacecraft/{spacecraftId}/refresh-visibility")
    fun refreshVisibility(
        @PathVariable spacecraftId: String,
        @RequestParam(required = false) noradId: Long?
    ) {
        visibilityRefreshJobService.enqueue(spacecraftId, noradId, "TEST_CONTROLLER")
    }

    /** Возвращает вычисленную on-demand проекцию будущей цепочки КА (диагностика). */
    @GetMapping("/spacecraft/{spacecraftId}/projection")
    fun getProjection(@PathVariable spacecraftId: String): List<PlanResponse> =
        planProjectionService.project(spacecraftId).map(PlanResponse::projected)

    /** Инжектит decision event через тот же use case, что Kafka consumer. */
    @PostMapping("/plan-decisions")
    fun handleDecision(@RequestBody message: PlanDecisionMessage) {
        handlePlanDecisionUseCase.handle(message)
    }

    /** Генерирует ACCEPTED/REJECTED decision event для active attempt указанного persisted plan. */
    @PostMapping("/plans/{planId}/decision")
    fun generatePlanDecision(
        @PathVariable planId: UUID,
        @RequestParam decision: PlanDecision,
        @RequestParam(required = false) reason: String?
    ): PlanDecisionMessage =
        testPlanDecisionService.generateDecision(planId, decision, reason)

    /** Генерирует событие «план заложен» (AWAITING_LAYIN → LAID_IN) для указанного persisted plan. */
    @PostMapping("/plans/{planId}/confirm-layin")
    fun confirmLayin(
        @PathVariable planId: UUID,
        @RequestParam(required = false) reason: String?
    ): PlanExecutionFeedbackMessage =
        testPlanDecisionService.generateLayinConfirmed(planId, reason)

    /** Загружает cache аппаратов из переданного в теле root-array payload НСИ вместо запроса в НСИ. */
    @PostMapping("/platforms/load-manual")
    fun loadPlatformsFromPayload(@RequestBody platforms: List<NsiPlatformDto>): TestPlatformsLoadResponse {
        val loaded = platformService.loadPlatformsFromNsiPayload(platforms)
        return TestPlatformsLoadResponse(
            loadedCount = loaded.size,
            allowedCount = platformService.loadAllowedPlatforms().size
        )
    }

    /** Загружает raw payload окон видимости из баллистики для диагностики. */
    @GetMapping("/external-points/{noradId}")
    fun getExternalPoints(
        @PathVariable noradId: Long,
        @RequestParam("time_start") timeStart: LocalDateTime,
        @RequestParam("time_stop") timeStop: LocalDateTime
    ): String =
        externalPointsClient.fetchRawVisibilityPayload(noradId, timeStart, timeStop)

    /** Возвращает persisted plan для проверки результата ручных операций. */
    @GetMapping("/plans/{planId}")
    fun getPlan(@PathVariable planId: UUID): PlanResponse =
        PlanResponse.from(planQueryService.getByPlanId(planId))
}

data class TestPlatformsLoadResponse(
    val loadedCount: Int,
    val allowedCount: Int
)
