package space.nstart.pcp.pcp_satellites_service.controller

import jakarta.validation.Valid
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.DeleteMapping
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.ResponseStatus
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestHeader
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.pcp_satellites_service.dto.ComplexPlanRunFilterDTO
import space.nstart.pcp.pcp_satellites_service.dto.ComplexPlanRunResponseDTO
import space.nstart.pcp.pcp_satellites_service.entity.ComplexPlanRunStatus
import space.nstart.pcp.pcp_satellites_service.service.ComplexMissionService
import space.nstart.pcp.pcp_satellites_service.service.ComplexPlanRunPersistenceService
import space.nstart.pcp.pcp_satellites_service.service.ComplexPlanRunOrchestrationService
import space.nstart.pcp.pcp_satellites_service.service.ComplexPlanRunQueryService
import space.nstart.pcp.pcp_satellites_service.service.SatelliteModeQueryService
import space.nstart.pcp.pcp_types_lib.dto.requests.ComplexPlanProcessRequestDTO
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.SlotCoverageStrategy
import tools.jackson.databind.json.JsonMapper
import java.time.LocalDateTime
import kotlin.system.measureTimeMillis

@RestController
@RequestMapping("/api/com-plan")
class ComplexPlanController {

    private val logger = LoggerFactory.getLogger(this::class.java)
    private val objectMapper = JsonMapper.builder().findAndAddModules().build()

    @Autowired
    private lateinit var complexMissionService: ComplexMissionService

    @Autowired
    private lateinit var complexPlanRunOrchestrationService: ComplexPlanRunOrchestrationService

    @Autowired
    private lateinit var complexPlanRunPersistenceService: ComplexPlanRunPersistenceService

    @Autowired
    private lateinit var complexPlanRunQueryService: ComplexPlanRunQueryService

    @Autowired
    private lateinit var satelliteModeQueryService: SatelliteModeQueryService

    @PostMapping("/process")
    fun calc(
        @Valid @RequestBody body: ComplexPlanProcessRequestDTO,
        @RequestHeader(name = "X-Requested-By", required = false) requestedByHeader: String?,
        @RequestHeader(name = "X-User", required = false) xUserHeader: String?,
        @RequestHeader(name = "X-Forwarded-User", required = false) forwardedUserHeader: String?
    ): ComplexPlanRunResponseDTO {
        val requestedBy = requestedByHeader
            ?: xUserHeader
            ?: forwardedUserHeader
        val request = body.copy(coverageStrategy = body.coverageStrategy ?: SlotCoverageStrategy.GREEDY)
        logger.info(
            "Complex plan process request started: interval=[{} - {}], satelliteId={}, satelliteIds={}, coverageSource={}, countLat={}, countLong={}, coverageStrategy={}, requestedBy={}",
            request.intervalStart,
            request.intervalEnd,
            request.satelliteId,
            request.satelliteIds,
            request.coverageSource,
            request.countLat,
            request.countLong,
            request.coverageStrategy,
            requestedBy
        )
        lateinit var response: ComplexPlanRunResponseDTO
        val durationMs = measureTimeMillis {
            response = complexPlanRunOrchestrationService.process(
                request = request,
                requestedBy = requestedBy
            )
        }
        logger.info(
            "Complex plan process completed: runId={}, status={}, durationMs={}, responseBody={}",
            response.runId,
            response.status,
            durationMs,
            objectMapper.writeValueAsString(response)
        )
        return response
    }

    @PostMapping("/clear")
    fun clear() = complexMissionService.clear()

    @GetMapping("/runs/{id}")
    fun run(@PathVariable id: Long) =
        complexPlanRunQueryService.getRun(id)

    @GetMapping("/runs/{id}/modes")
    fun runModes(@PathVariable id: Long) =
        satelliteModeQueryService.findModesByRun(id)

    @DeleteMapping("/runs/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    fun deleteRun(@PathVariable id: Long) {
        complexPlanRunPersistenceService.deleteRun(id)
    }

    @GetMapping("/runs")
    fun runs(
        @RequestParam(required = false) status: ComplexPlanRunStatus?,
        @RequestParam(required = false) createdFrom: LocalDateTime?,
        @RequestParam(required = false) createdTo: LocalDateTime?,
        @RequestParam(required = false) satelliteId: Long?,
        @RequestParam(required = false) intervalStart: LocalDateTime?,
        @RequestParam(required = false) intervalEnd: LocalDateTime?
    ) = complexPlanRunQueryService.findRuns(
        ComplexPlanRunFilterDTO(
            status = status,
            createdFrom = createdFrom,
            createdTo = createdTo,
            satelliteId = satelliteId,
            intervalStart = intervalStart,
            intervalEnd = intervalEnd
        )
    )

    @GetMapping("/cell-with-mars/{cell_number}")
    fun paintCellWithMars(@PathVariable("cell_number") cellNumber: Long) =
        satelliteModeQueryService.buildCellPaintGeometry(cellNumber)
}
