package space.nstart.pcp.pcp_satellites_service.controller

import org.springframework.beans.factory.annotation.Autowired
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.pcp_satellites_service.configuration.CustomErrorException
import space.nstart.pcp.pcp_satellites_service.configuration.CustomValidationException
import space.nstart.pcp.pcp_satellites_service.service.ComplexMissionService
import space.nstart.pcp.pcp_satellites_service.service.ComplexPlanQueryService
import space.nstart.pcp.pcp_satellites_service.service.SatelliteService
import space.nstart.pcp.pcp_types_lib.dto.requests.EarthCellCalculationRequestDTO
import java.time.LocalDateTime

@RestController
@RequestMapping("/api/satellites")
class SatelliteController {

    @Autowired
    private lateinit var complexMissionService: ComplexMissionService

    @Autowired
    private lateinit var satelliteService: SatelliteService

    @Autowired
    private lateinit var complexPlanQueryService: ComplexPlanQueryService

    @GetMapping
    fun all() = satelliteService.all()

    @GetMapping("/{satellite_id}")
    fun byId(@PathVariable("satellite_id") id: Long) = satelliteService.byId(id)

    @GetMapping("/{satellite_id}/mission")
    fun planById(@PathVariable("satellite_id") id: Long) =
        complexPlanQueryService.findMissionModes(requireSatelliteId(id))

    @GetMapping("/{satellite_id}/mission/statistics")
    fun missionStatistics(@PathVariable("satellite_id") id: Long) =
        complexPlanQueryService.missionStatistics(requireSatelliteId(id))

    @GetMapping("/{satellite_id}/mission-for-paint")
    fun planByIdForPaint(@PathVariable("satellite_id") id: Long) =
        complexPlanQueryService.buildPaintGeometry(requireSatelliteId(id))

    @GetMapping("/{satellite_id}/modes")
    fun modesBySatelliteAndInterval(
        @PathVariable("satellite_id") id: Long,
        @RequestParam("intervalStart") intervalStart: LocalDateTime,
        @RequestParam("intervalEnd") intervalEnd: LocalDateTime,
        @RequestParam("runId", required = false) runId: Long?
    ) = complexPlanQueryService.findModesByInterval(
        listOf(requireSatelliteId(id)),
        intervalStart,
        intervalEnd,
        runId
    )

    @GetMapping("/{satellite_id}/snapshots")
    fun snapshotsBySatellite(
        @PathVariable("satellite_id") id: Long,
        @RequestParam("intervalStart", required = false) intervalStart: LocalDateTime?,
        @RequestParam("intervalEnd", required = false) intervalEnd: LocalDateTime?,
        @RequestParam("activeOnly", defaultValue = "false") activeOnly: Boolean
    ) = complexPlanQueryService.findSnapshots(
        satelliteId = requireSatelliteId(id),
        intervalStart = intervalStart,
        intervalEnd = intervalEnd,
        activeOnly = activeOnly
    )

    @GetMapping("/{satellite_id}/snapshots/active")
    fun activeSnapshotBySatellite(
        @PathVariable("satellite_id") id: Long,
        @RequestParam("intervalStart", required = false) intervalStart: LocalDateTime?,
        @RequestParam("intervalEnd", required = false) intervalEnd: LocalDateTime?
    ) = complexPlanQueryService.findActiveSnapshot(
        satelliteId = requireSatelliteId(id),
        intervalStart = intervalStart,
        intervalEnd = intervalEnd
    )

    @GetMapping("/snapshots")
    fun snapshots(
        @RequestParam("satelliteId", required = false) satelliteId: Long?,
        @RequestParam("intervalStart", required = false) intervalStart: LocalDateTime?,
        @RequestParam("intervalEnd", required = false) intervalEnd: LocalDateTime?,
        @RequestParam("activeOnly", defaultValue = "false") activeOnly: Boolean
    ) = complexPlanQueryService.findSnapshots(
        satelliteId = satelliteId,
        intervalStart = intervalStart,
        intervalEnd = intervalEnd,
        activeOnly = activeOnly
    )

    @GetMapping("/snapshots/{snapshot_id}")
    fun snapshot(
        @PathVariable("snapshot_id") snapshotId: Long
    ) = complexPlanQueryService.findSnapshot(snapshotId)

    @GetMapping("/snapshots/{snapshot_id}/modes")
    fun modesBySnapshot(
        @PathVariable("snapshot_id") snapshotId: Long,
        @RequestParam("intervalStart", required = false) intervalStart: LocalDateTime?,
        @RequestParam("intervalEnd", required = false) intervalEnd: LocalDateTime?
    ) = complexPlanQueryService.findModesBySnapshot(snapshotId, intervalStart, intervalEnd)

    @GetMapping("/modes")
    fun modesByInterval(
        @RequestParam("intervalStart") intervalStart: LocalDateTime,
        @RequestParam("intervalEnd") intervalEnd: LocalDateTime,
        @RequestParam("satelliteId", required = false) satelliteId: Long?,
        @RequestParam("satelliteIds", required = false) satelliteIds: List<Long>?
    ) = complexPlanQueryService.findModesByInterval(
        buildSatelliteFilter(satelliteId, satelliteIds),
        intervalStart,
        intervalEnd
    )

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

    private fun buildSatelliteFilter(satelliteId: Long?, satelliteIds: List<Long>?): List<Long> {
        val ids = buildList {
            satelliteId?.let { add(it) }
            satelliteIds?.let { addAll(it) }
        }.distinct()

        if (ids.isEmpty()) {
            throw CustomValidationException("Необходимо задать satelliteId или satelliteIds")
        }

        return ids
    }

    private fun requireSatelliteId(id: Long): Long {
        satelliteService.byId(id) ?: throw CustomErrorException("Нет КА с заданным идентификаторм $id")
        return id
    }
}
