package space.nstart.pcp.pcp_satellites_service.model

import ballistics.flightLine.PointOnEarthCalculator
import ballistics.orbitalPoints.timeStepper.RungeStepper
import ballistics.types.EarthType
import ballistics.types.ModDVType
import ballistics.types.OrbitalPoint
import ballistics.types.Orientation
import ballistics.types.THBLPoint
import ballistics.types.WorkCSType
import org.locationtech.jts.geom.Coordinate
import org.locationtech.jts.geom.GeometryFactory
import org.locationtech.jts.io.WKTWriter
import org.springframework.stereotype.Component
import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SquareViewParamDTO
import space.nstart.pcp.pcp_types_lib.dto.satellite.SatelliteInfoDTO
import java.time.LocalDate
import java.time.LocalDateTime
import kotlin.div
import kotlin.math.ceil
import kotlin.math.PI
import kotlin.times


@Component
class SatelliteModel(
    val satelliteId : Long = 0,
    val name : String = "",
    val red : Short = 255,
    val green : Short = 0,
    val blue : Short = 0,
    val longMission : LongTermMission = LongTermMission(),
    val bls: BLS = BLS(),
    val scanTLE : Boolean = false
) {

    fun toDTO() = SatelliteInfoDTO(
        satelliteId,
        name,
        red,
        green,
        blue,
        bls.captureAngle,
        scanTLE,
        bls.durationMax.toLong(),
        ceil(bls.mmi).toLong()
    )


    fun contourByTime(
            tn : Double,
            roll: Double,
            capture : Double,
            points : List<OrbitalPoint>
    ) : String {



        return ""
    }


    fun contour(
        tn : Double,
        tk : Double,
        roll: Double,
        capture : Double,
        points : List<OrbitalPoint>) : String{
        //val vp = points.filter { p -> p.t>=tn && p.t <= tk }
        val stepper: RungeStepper = RungeStepper(points.toMutableList(), EarthType.PZ90d02)
        var  t = tn
        val vp = mutableListOf<OrbitalPoint>()
        while(t <= tk) {
            stepper.calculate(t)?.let { vp.add(it) }

            t += 1.0
        }
        val r = vp.map {
            viewParams(it, roll + capture, 0.0) ?: THBLPoint(
                0.0,
                0.0,
                0.0,
                0.0
            )
        }
        val l = vp.map {
            viewParams(it, roll - capture, 0.0) ?: THBLPoint(
                0.0,
                0.0,
                0.0,
                0.0
            )
        }
        val geom = mutableListOf<Coordinate>()
        for (rp in r)
            geom.add(Coordinate(rp.long * 180 / PI, rp.lat * 180 / PI, 0.0))
        for (lp in l.reversed())
            geom.add(Coordinate(lp.long * 180 / PI, lp.lat * 180 / PI, 0.0))
        if (!geom.isEmpty())
            geom.add(Coordinate(geom.first().x, geom.first().y))
        val geometryFactory = GeometryFactory()
        val shell = geometryFactory.createLinearRing(geom.toTypedArray())
        val polygon = geometryFactory.createPolygon(shell)
        val wktWriter = WKTWriter()
        return wktWriter.write(polygon)
    }

    fun viewParams(pos : OrbitalPoint, gamma : Double, tang : Double) : THBLPoint?{
        val calculator = PointOnEarthCalculator(EarthType.PZ90d02, WorkCSType.WCSOrbit)
        return calculator.pointOnEarth(pos, Orientation(tang * PI / 180.0, gamma * PI / 180.0, 0.0))
    }

    fun hasResources(dat : LocalDate) : Boolean{
        if (longMission.surveys
                .filter { it.time.toLocalDate() == dat }
                .sumOf { view -> view.duration } >= bls.dailyMaxDuration - bls.durationMin
        )
            return false
        return true
    }

    fun canBeUsed(view : SquareViewParamDTO) : Boolean{

        if (longMission.surveys
            .filter { it.time.toLocalDate() == view.timeBegin.toLocalDate() }
            .sumOf { view -> view.duration } > bls.dailyMaxDuration
            )
            return false
        if (longMission.surveys
                .filter { it.revolution == view.revolutionBegin }
                .sumOf { view -> view.duration } > bls.revolutionMaxDuration
            )
            return false
//        val intersections = longMission.surveys
//            .filter { surv ->
//                val tn1 = surv.time.plusSeconds(surv.duration.toLong() + bls.mmi.toLong())
//                val tk1 = surv.time.minusSeconds(bls.mmi.toLong())
//                val tn2 = view.timeBegin
//                val tk2 = view.timeEnd
//
//                val intersects = (tk1 <= tn2 && tk2 <= tn1)
//                intersects
//            }
//        return intersections.isEmpty()
        return true
    }
}
