package space.nstart.pcp_tgu_service.integration.api

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.stereotype.Component
import space.nstart.pcp_tgu_service.domain.InsertionPoint
import space.nstart.pcp_tgu_service.domain.ObservationWindow
import space.nstart.pcp_tgu_service.domain.SpacecraftPoints
import space.nstart.pcp_tgu_service.dto.ExternalRvaItemDto
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeParseException
import java.time.temporal.ChronoUnit

/**
 * Парсит raw payload баллистики в доменную модель расчёта без доступа к БД.
 */
@Component
class VisibilityPayloadParser(
    private val objectMapper: ObjectMapper
) {

    /** Группирует RVA records по станциям и сортирует окна для алгоритма планирования. */
    fun parse(spacecraftId: String, payloadJson: String): SpacecraftPoints {
        val response = objectMapper.readValue(payloadJson, Array<ExternalRvaItemDto>::class.java).toList()
        val points = response
            .groupBy { item -> item.stationId }
            .map { (stationId, items) ->
                InsertionPoint(
                    pointId = stationId.toString(),
                    observationWindows = items.map { item ->
                        ObservationWindow(
                            startTime = toLocalDateTime(item.onStart.time),
                            endTime = toLocalDateTime(item.onStop.time),
                            elevationAngle = item.onMaximum.elevation
                        )
                    }.sortedBy { window -> window.startTime }
                )
            }
            .sortedBy { point -> point.pointId }

        return SpacecraftPoints(spacecraftId = spacecraftId, points = points)
    }

    /**
     * Разбирает ISO-строку времени баллистики в naive `LocalDateTime`.
     *
     * Если время приходит с зоной (`...Z`/офсет), момент проецируем в локальный пояс JVM
     * (`ZoneId.systemDefault()`): naive-время в системе — настенные часы локальной зоны, в которой
     * работают все сервисы, без UTC-семантики. Naive-строку без зоны берём как есть.
     *
     * Обрезаем до микросекунд — это эффективная точность системы: `planned_plan.start_time/end_time`
     * хранятся как Postgres `timestamp(6)`, при записи наносекундный хвост баллистики всё равно теряется.
     * Без обрезки проекция (наносекунды) и persisted-планы (микросекунды) перестают совпадать по
     * бизнес-ключу — ломается дедуп в read-пути и матчинг базы в [calculatePlansAfter].
     */
    private fun toLocalDateTime(value: String): LocalDateTime =
        try {
            LocalDateTime.ofInstant(Instant.parse(value), ZoneId.systemDefault())
        } catch (_: DateTimeParseException) {
            LocalDateTime.parse(value)
        }.truncatedTo(ChronoUnit.MICROS)
}
