package ballistics.orbitalPoints.integrator.modDv

import ballistics.types.AstroType
import ballistics.types.BallisticsError
import ballistics.types.EarthType
import ballistics.utils.astro.AstronomerJ2000
import ballistics.utils.atmosphere.Atmosphere2004
import ballistics.utils.math.Vector3D
import java.time.LocalDateTime
import java.time.ZoneOffset
import kotlin.math.cos
import kotlin.math.sin

internal open class MDVKondor(
    earthType: EarthType,
    var astroType: AstroType,
    var garmonics: Int,
    var isProgn: Boolean,
) : MDVBars(earthType) {
    protected val amax = 0.6378136E+7
    protected val alpha = 3.3528037E-3F

    protected var astro = AstronomerJ2000(earthType)
    protected var atm2004 = Atmosphere2004()

    override fun calculate(x: Array<Double>): BallisticsError {
        prepare(x)
        y[0] = oma * x[3] + earth.wEarth * x[1] * 2
        y[1] = oma * x[4] - earth.wEarth * x[0] * 2
        y[2] = bca * x[5]

        y[3] = x[0]
        y[4] = x[1]
        y[5] = x[2]

        if (!isProgn) {
            // УЧЕТ АТМОСФЕРЫ //

            var rb1: Double = fik * alpha
            rb1 = 1.0 - rb1
            rb1 *= amax
            val h: Double = r - rb1
            if (h < hminimum) {
                return BallisticsError.H_MINIMUM_ERROR
            }

            var sun = astro.sunCoordinates(x[6])
            sun = astro.askToGrinvich(sun, x[6]).basis()

            var day = (LocalDateTime.ofEpochSecond(x[6].toLong(), 0, ZoneOffset.UTC).dayOfYear - 1).toDouble()

            var ro = atm2004.atm2004Kav(f81, day, h, x, sun.x, sun.y, sun.z)

            var srv = v * ro * sBall

            y[0] -= srv * x[0]
            y[1] -= srv * x[1]
            y[2] -= srv * x[2]
        }
        // УЧЕТ АНОМАЛИЙ ГЕОПОТЕНЦИАЛА //

        var xyz = Vector3D(0.0, 0.0, 0.0)
        var rez: BallisticsError = geopotential.anomkond(x, garmonics, garmonics, xyz)
        if (rez != BallisticsError.OK) {
            return rez
        }

        y[0] = y[0] + xyz.x / 1000000.0
        y[1] = y[1] + xyz.y / 1000000.0
        y[2] = y[2] + xyz.z / 1000000.0

        if (!isProgn) {
            // УЧЕТ Луны и Солнца
            var tsol = astro.si2000(x[6])

            val cg: Double = cos(tsol)
            val sg: Double = sin(tsol)

            // Перевод из ОГЭСК в АГЭСК

            // Перевод из ОГЭСК в АГЭСК
            val x2: Double = (x[3] * cg - x[4] * sg) / 1000.0
            val y2: Double = (x[3] * sg + x[4] * cg) / 1000.0
            val z2: Double = x[5] / 1000.0

            var cor = astro.sunMoonCorrection(x[6], x2, y2, z2)
            var ddx = (cor.x * cg + cor.y * sg) * 1000.0
            var ddy = (cor.y * cg - cor.x * sg) * 1000.0
            var ddz = cor.z * 1000.0

            y[0] = y[0] + ddx // Учет влияния Солнца и Луны
            y[1] = y[1] + ddy
            y[2] = y[2] + ddz
        }

        return BallisticsError.OK
    }
}

