package space.nstart.pcp.pcp_request_service.service

import ballistics.Ballistics
import ballistics.types.BallisticsError
import ballistics.types.InitialConditions
import ballistics.types.ModDVType
import ballistics.types.OrbitalPoint
import ballistics.types.PPI
import ballistics.types.VisibilityParametersZRV
import ballistics.types.ZRV
import ballistics.utils.fromDateTime
import ballistics.utils.math.Vector3D
import ballistics.utils.toDateTime
import org.springframework.stereotype.Service
import space.nstart.pcp.pcp_request_service.configuration.CustomErrorException
import space.nstart.pcp.pcp_types_lib.dto.ballistics.IcRvaRequestDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.RadioVisibilityAreaDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TargetPositionDTO
import kotlin.math.PI


@Service
class RVAService {



    fun calculateRVA(icRvaRequest : IcRvaRequestDTO) : List<RadioVisibilityAreaDTO> {


        val bal = Ballistics()
        val mdv = ModDVType.fromInt((icRvaRequest.modDvType ?: 1).toInt())

        bal.modDVType = mdv
        var result = bal.calculateOrbPoints(
            InitialConditions(
                OrbitalPoint(
                    fromDateTime(icRvaRequest.ic.orbPoint.time),
                    icRvaRequest.ic.orbPoint.revolution.toInt(),
                    Vector3D(
                        icRvaRequest.ic.orbPoint.x,
                        icRvaRequest.ic.orbPoint.y,
                        icRvaRequest.ic.orbPoint.z,
                    ),
                    Vector3D(
                        icRvaRequest.ic.orbPoint.vx,
                        icRvaRequest.ic.orbPoint.vy,
                        icRvaRequest.ic.orbPoint.vz,
                    )
                ),
                icRvaRequest.ic.sBall,
                icRvaRequest.ic.f81
            ),
            fromDateTime(icRvaRequest.timeStart),
            fromDateTime(icRvaRequest.timeStop)
        )

        if (result != BallisticsError.OK)
            throw CustomErrorException("Ошибка расчета ПДЦМ. Код ошибки : $result")

        result = bal.calculateZRV(
            listOf(
                PPI(
                    1, 1,
                    icRvaRequest.station.position.lat / 180 * PI,
                    icRvaRequest.station.position.long / 180 * PI,
                    icRvaRequest.station.position.height,
                    icRvaRequest.station.elevationMin / 180 * PI,
                    icRvaRequest.station.elevationMax / 180 * PI,
                    null, null
                )
            ),
            fromDateTime(icRvaRequest.timeStart),
            fromDateTime(icRvaRequest.timeStop)
        )
        if (result != BallisticsError.OK)
            throw CustomErrorException("Ошибка расчета ЗРВ. Код ошибки : $result")

        return bal.zrv.map { mkRVA(it, 0L) }
    }


    fun mkTP(p : VisibilityParametersZRV) = TargetPositionDTO(
        toDateTime(p.t),
        p.elevation * 180 / PI,
        p.azimuth * 180 / PI,
        p.range
    )

    fun mkRVA(p : ZRV, id : Long) = RadioVisibilityAreaDTO(
        noradId = id,
        stationId = p.ppi.toLong(),
        revolution = p.vit.toLong(),
        onStart = mkTP(p.zoneIn),
        onMaximum = mkTP(p.zoneMax),
        onStop = mkTP(p.zoneOut)
    )
}