package space.nstart.pcp.slots_service.service

import org.springframework.beans.factory.ObjectProvider
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.bodyToMono
import org.springframework.web.reactive.function.client.bodyToFlux
import space.nstart.pcp.pcp_types_lib.dto.satellite.mission.MissionRequestDTO
import space.nstart.pcp.pcp_types_lib.dto.satellite.mission.MissionResponseDTO
import space.nstart.pcp.pcp_types_lib.dto.satellite.mission.MissionSurveyCalculationResponseDTO
import space.nstart.pcp.pcp_types_lib.dto.satellite.mission.ModeResponseDTO
import space.nstart.pcp.slots_service.dto.currentplans.CurrentPlansMissionPageDTO
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
import java.util.UUID
import java.time.LocalDateTime


@Service
class MissionService(webClientBuilderProvider: ObjectProvider<WebClient.Builder>) {
    private val webClientBuilder: WebClient.Builder = webClientBuilderProvider.ifAvailable ?: WebClient.builder()

    @Value("\${settings.mission-service:pcp-complex-mission-service}")
    val url = ""

    fun plan(sat : Long, tn : LocalDateTime, tk : LocalDateTime) =
        webClientBuilder.build()
            .get()
            .uri("$url/api/missions/modes/satellite?satellite_id=$sat&timeStart=${UtcDateTimes.format(tn)}&timeStop=${UtcDateTimes.format(tk)}")
            .retrieve()
            .bodyToFlux<ModeResponseDTO>()

    fun allMissions(): List<MissionResponseDTO> =
        webClientBuilder.build()
            .get()
            .uri("$url/api/missions")
            .retrieve()
            .bodyToFlux(MissionResponseDTO::class.java)
            .collectList()
            .block()
            ?: emptyList()

    fun missionsBySatellite(satelliteId: Long, page: Int, size: Int): CurrentPlansMissionPageDTO {
        val normalizedPage = page.coerceAtLeast(0)
        val normalizedSize = size.coerceIn(1, 100)
        val filtered = allMissions()
            .asSequence()
            .filter { it.satelliteId == satelliteId }
            .sortedWith(
                compareByDescending<MissionResponseDTO> { it.missionStart ?: it.missionStop ?: LocalDateTime.MIN }
                    .thenByDescending { it.missionStop ?: LocalDateTime.MIN }
                    .thenByDescending { it.missionId.toString() }
            )
            .toList()

        val from = (normalizedPage * normalizedSize).coerceAtMost(filtered.size)
        val to = (from + normalizedSize).coerceAtMost(filtered.size)
        val totalPages = if (filtered.isEmpty()) 0 else ((filtered.size - 1) / normalizedSize) + 1

        return CurrentPlansMissionPageDTO(
            satelliteId = satelliteId,
            page = normalizedPage,
            size = normalizedSize,
            totalElements = filtered.size,
            totalPages = totalPages,
            items = filtered.subList(from, to)
        )
    }


    fun createMission(body: MissionRequestDTO): MissionResponseDTO =
        webClientBuilder.build()
            .post()
            .uri("$url/api/missions")
            .bodyValue(body)
            .retrieve()
            .bodyToMono<MissionResponseDTO>()
            .block()
            ?: error("Mission service returned empty response while creating mission")

    fun calculateSurveys(missionId: UUID, comPlanSnapshotId: Long? = null): MissionSurveyCalculationResponseDTO {
        val targetUrl = buildString {
            append("$url/api/missions/$missionId/surveys/calculate")
            if (comPlanSnapshotId != null) {
                append("?comPlanSnapshotId=")
                append(comPlanSnapshotId)
            }
        }
        return webClientBuilder.build()
            .post()
            .uri(targetUrl)
            .retrieve()
            .bodyToMono<MissionSurveyCalculationResponseDTO>()
            .block()
            ?: error("Mission service returned empty survey calculation response")
    }

    fun calculateDrops(missionId: UUID) {
        webClientBuilder.build()
            .post()
            .uri("$url/api/missions/$missionId/drops/calculate")
            .retrieve()
            .toBodilessEntity()
            .block()
    }

    fun confirmMission(missionId: UUID) {
        webClientBuilder.build()
            .post()
            .uri("$url/api/missions/$missionId/confirm")
            .retrieve()
            .toBodilessEntity()
            .block()
    }

    fun modesByMission(missionId: UUID): List<ModeResponseDTO> =
        webClientBuilder.build()
            .get()
            .uri("$url/api/missions/$missionId/modes")
            .retrieve()
            .bodyToFlux<ModeResponseDTO>()
            .collectList()
            .block()
            ?: emptyList()

}
