package space.nstart.pcp_tgu_service.integration.api

import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.server.ResponseStatusException
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
import space.nstart.pcp_tgu_service.config.MissionPlaningProperties
import java.time.Duration
import java.time.LocalDateTime
import java.util.UUID

data class MissionCloneRequest(
    val mode: String,
    val windowStart: LocalDateTime? = null,
    val windowStop: LocalDateTime? = null
)

data class MissionCloneResponse(val newMissionId: UUID)

data class MissionBlankRequest(
    val satelliteId: Long,
    val missionStart: LocalDateTime,
    val missionStop: LocalDateTime
)

private data class MissionCloneOutboundRequest(
    val mode: String,
    val windowStart: String? = null,
    val windowStop: String? = null
)

private data class MissionBlankOutboundRequest(
    val satelliteId: Long,
    val missionStart: String,
    val missionStop: String
)

@Component
class MissionPlaningClient(
    properties: MissionPlaningProperties,
    webClientBuilder: WebClient.Builder
) {

    private val webClient: WebClient = webClientBuilder
        .baseUrl(properties.baseUrl)
        .build()

    private val timeout: Duration = Duration.ofSeconds(30)

    fun cloneMission(missionId: UUID, req: MissionCloneRequest): MissionCloneResponse =
        webClient.post()
            .uri("/api/missions/{id}/clone", missionId)
            .bodyValue(req.toOutbound())
            .retrieve()
            .onStatus({ it.isError }) { resp ->
                resp.bodyToMono(String::class.java).defaultIfEmpty("").map { body ->
                    // 4xx апстрима пробрасываем как есть (404 — нет базовой миссии и т.п.),
                    // 5xx сворачиваем в 502: проблема не в запросе оператора, а в mission-planing.
                    val status = if (resp.statusCode().is5xxServerError) HttpStatus.BAD_GATEWAY
                    else HttpStatus.valueOf(resp.statusCode().value())
                    ResponseStatusException(status, "Клон миссии $missionId не удался (${resp.statusCode()}): $body")
                }
            }
            .bodyToMono(MissionCloneResponse::class.java)
            .block(timeout)
            ?: throw ResponseStatusException(
                HttpStatus.BAD_GATEWAY,
                "Пустой ответ mission-planing на клон миссии $missionId"
            )

    private fun MissionCloneRequest.toOutbound(): MissionCloneOutboundRequest = MissionCloneOutboundRequest(
        mode = mode,
        windowStart = windowStart?.let(UtcDateTimes::format),
        windowStop = windowStop?.let(UtcDateTimes::format)
    )

    private fun MissionBlankRequest.toOutbound(): MissionBlankOutboundRequest = MissionBlankOutboundRequest(
        satelliteId = satelliteId,
        missionStart = UtcDateTimes.format(missionStart),
        missionStop = UtcDateTimes.format(missionStop)
    )

    /** Создаёт пустую миссию на окно (план новой цепочки «без истории»). */
    fun createBlankMission(req: MissionBlankRequest): MissionCloneResponse =
        webClient.post()
            .uri("/api/missions/blank")
            .bodyValue(req.toOutbound())
            .retrieve()
            .onStatus({ it.isError }) { resp ->
                resp.bodyToMono(String::class.java).defaultIfEmpty("").map { body ->
                    val status = if (resp.statusCode().is5xxServerError) HttpStatus.BAD_GATEWAY
                    else HttpStatus.valueOf(resp.statusCode().value())
                    ResponseStatusException(status, "Создание пустой миссии не удалось (${resp.statusCode()}): $body")
                }
            }
            .bodyToMono(MissionCloneResponse::class.java)
            .block(timeout)
            ?: throw ResponseStatusException(
                HttpStatus.BAD_GATEWAY,
                "Пустой ответ mission-planing на создание пустой миссии"
            )

    /** Компенсация: удаляет клонированную миссию при сбое сохранения DRAFT-плана. Best-effort. */
    fun deleteMission(missionId: UUID) {
        webClient.delete()
            .uri("/api/missions/{id}", missionId)
            .retrieve()
            .toBodilessEntity()
            .block(timeout)
    }
}
