package ballistics.zrv

import ballistics.Ballistics
import ballistics.types.BallisticsError
import ballistics.types.EarthType
import ballistics.types.InitialConditions
import ballistics.types.IntegrationType
import ballistics.types.ModDVType
import ballistics.types.OrbitalPoint
import ballistics.types.PPI
import ballistics.types.TLE
import ballistics.utils.math.Vector3D
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.time.LocalDateTime
import java.time.ZoneOffset
import kotlin.math.PI

internal class ZRVStepperCalculatorTest {
    @Test
    fun `calculate keeps different revolutions for consecutive TLE visibility zones`() {
        val ballistics = Ballistics()
        val tle = TLE(
            "1 25994U 99068A   26167.13049375  .00000315  00000-0  73126-4 0  9997",
            "2 25994  97.9457 216.7186 0001501 193.3628 244.8059 14.61102329409455",
        )
        val timeStart = LocalDateTime.of(2026, 6, 16, 10, 41, 50, 189_000_000).toEpochSecond(ZoneOffset.UTC).toDouble()
        val timeStop = LocalDateTime.of(2026, 6, 18, 0, 41, 50, 189_000_000).toEpochSecond(ZoneOffset.UTC).toDouble()

        assertEquals(BallisticsError.OK, ballistics.calculateOrbPoints(tle, timeStart, timeStop))
        assertEquals(
            BallisticsError.OK,
            ballistics.calculateZRV(
                listOf(
                    PPI(
                        1,
                        0,
                        69.038863 * PI / 180.0,
                        32.861553 * PI / 180.0,
                        124.67,
                        5 * PI / 180.0,
                        90 * PI / 180.0,
                    ),
                ),
                timeStart,
                timeStop,
            ),
        )

        val zones = ballistics.zrv.toList()
        val firstZone = zones.first {
            it.zoneIn.t >= LocalDateTime.of(2026, 6, 16, 14, 0).toEpochSecond(ZoneOffset.UTC) &&
                it.zoneIn.t < LocalDateTime.of(2026, 6, 16, 15, 0).toEpochSecond(ZoneOffset.UTC)
        }
        val secondZone = zones.first {
            it.zoneIn.t >= LocalDateTime.of(2026, 6, 16, 15, 0).toEpochSecond(ZoneOffset.UTC) &&
                it.zoneIn.t < LocalDateTime.of(2026, 6, 16, 17, 0).toEpochSecond(ZoneOffset.UTC)
        }

        assertEquals(firstZone.vit + 1, secondZone.vit)
    }

    @Test
    fun calculate() {
        val r = Ballistics()


        val p = r.getTLEParams(TLE("1 62141U 24224C   25324.24196334  .00027917  00000-0  10193-2 0  9998",
            "2 62141  42.9988  56.0174 0001022  26.8436 333.2469 15.27609213 55582"), "test")





        r.earthType = EarthType.PZ90d02
        r.modDVType = ModDVType.BARS
        r.integrationType = IntegrationType.ADAMS7

        val mnu = mutableListOf<InitialConditions>()
        mnu.add(
            InitialConditions(
                OrbitalPoint(
                    LocalDateTime.of(2021, 12, 3, 0, 5, 45, 0).toEpochSecond(ZoneOffset.UTC).toDouble(),
                    1,
                    Vector3D(
                        -5357933.7872,
                        4328646.1787,
                        0.0,
                    ),
                    Vector3D(
                        941.8995373,
                        1150.6919822,
                        7544.9920840,
                    ),
                ),
                0.0061,
                125.0,
            ),
        )
        var rez = r.calculateOrbPoints(mnu.toTypedArray(), mnu.first().point.t, mnu.first().point.t + 86400.0 * 3)
        if (rez == BallisticsError.OK) {
            rez =
                r.calculateZRV(
                    listOf(
                        PPI(
                            1,
                            1,
                            55.15 * PI / 180,
                            38.39 * PI / 180,
                            0.0,
                            5 * PI / 180,
                            80 * PI / 180,
//                shadowMin = listOf(
//                    ShadowAU(110.0 * PI / 180, 150 * PI / 180, 25 * PI / 180),
//                    ShadowAU(175.0 * PI / 180, 183 * PI / 180, 90 * PI / 180),
//                ),
//                shadowMax = listOf(
//                    ShadowAU(189.0 * PI / 180, 192 * PI / 180, 0 * PI / 180),
//                )
                        ),
                    ),
                    mnu.first().point.t,
                    mnu.first().point.t + 86400.0 * 3,
                )

            if (rez == BallisticsError.OK) {
                for (z in r.zrv)
                    println(
                        " ${z.vit} \t" +
                            " ${z.au} \t" +
                            " ${LocalDateTime.ofEpochSecond(z.zoneIn.t.toLong(), 0, ZoneOffset.UTC)}  \t" +
                            " ${z.zoneIn.azimuth * 180 / PI} \t" +
                            " ${z.zoneIn.elevation * 180 / PI} \t" +
                            " ${LocalDateTime.ofEpochSecond(z.zoneOut.t.toLong(), 0, ZoneOffset.UTC)} \t" +
                            " ${z.zoneOut.azimuth * 180 / PI} \t" +
                            " ${z.zoneOut.elevation * 180 / PI} \t" +
                            " ${LocalDateTime.ofEpochSecond(z.zoneMax.t.toLong(), 0, ZoneOffset.UTC)} \t" +
                            " ${z.zoneMax.azimuth * 180 / PI} \t" +
                            " ${z.zoneMax.elevation * 180 / PI} \t",
                    )
            }
        }

        assertTrue((rez == BallisticsError.OK))
    }
}
