package space.nstart.pcp.angularmotion

import ballistics.types.BLHPoint
import ballistics.types.OrbitalPoint
import ballistics.types.Orientation
import ballistics.utils.math.Quaternion3D
import ballistics.utils.math.Vector3D

/**
 * Параметры блока состояния КА, перенесенные из sBLS_KA проекта OrbitalMotion.
 * Угловые величины задаются в радианах, линейные параметры оптики — в миллиметрах.
 */
data class AngularMotionConfig(
    /** Фокусное расстояние, мм. */
    val focus: Double = 5500.0,
    /** Шаг записи СДИ, с. */
    val stepSdi: Double = 20.0,
    /** Дискретность расчета ПУУД, с. */
    val stepPuud: Double = 0.125,
    /** Дискретность времени начала режима, с. */
    val discreteTimes: Double = 0.125,
    /** Длительность интервала успокоения, с. */
    val tau: Double = 10.0,
    /** Расстояние от центра ОЭП до центра фокальной плоскости телескопа, мм. */
    val dxOep: Double = 37.5,
    /** Длина линейки ОЭП, мм. */
    val dlOep: Double = 162.0,
)

enum class AngularMotionMode {
    CONST_ORIENT,
    AZIMUTH,
    SMOOTH_SDI,
}

/**
 * ИД на построение программы управления угловым движением.
 * Поля соответствуют sSurveyID из OrbitalMotion, но без Qt-типов и AIST-префиксов.
 */
data class SurveyId(
    /** Признаки включения ОЭП: 1..4. */
    val oep: List<Boolean> = listOf(false, false, false, false),
    /** Примерное интегральное время начала наблюдения, с. */
    val t: Double = 0.0,
    /** Координаты точки прицеливания: широта/долгота в радианах, высота в метрах. */
    val b: Double = 0.0,
    val l: Double = 0.0,
    val h: Double = 0.0,
    /** Длительность включения, с. */
    val duration: Double = 0.0,
    /** Массив СДИ. Используется режимами AZIMUTH и SMOOTH_SDI. */
    val sdi: List<Double> = emptyList(),
    /** Азимут сканирования, рад. */
    val azimuth: Double = 0.0,
    /** Упреждающий угол, рад. */
    val uprAngle: Double = 0.0,
    /** Поместить точку прицеливания в центр маршрута. */
    val pointInCenter: Boolean = false,
)

/** Результирующие параметры работы ОЭП. */
data class OepResult(
    val state: Boolean = false,
    val tOn: Double = 0.0,
    val tOff: Double = 0.0,
)

/** Одна расчетная точка ПУУД. */
data class AngularMotionPoint(
    val t: Double,
    val orbitalPoint: OrbitalPoint,
    val orientation: Orientation,
    val groundPoint: BLHPoint?,
    val omega: Vector3D = Vector3D(),
    val eps: Vector3D = Vector3D(),
    val quaternion: Quaternion3D = Quaternion3D(1.0, 0.0, 0.0, 0.0),
    val wd: Vector3D = Vector3D(),
    val sdi: Double = 0.0,
    /** СДИ на левом краю линейки ОЭП, мм/с. */
    val sdiLeft: Double? = null,
    /** СДИ на правом краю линейки ОЭП, мм/с. */
    val sdiRight: Double? = null,
    /** Максимальное отклонение краевой СДИ от центральной, мм/с. */
    val sdiSpread: Double? = null,
)

/** Полный результат расчета режима углового движения. */
data class AngularMotionResult(
    val mode: AngularMotionMode,
    val startTime: Double,
    val points: List<AngularMotionPoint>,
    val tauPoints: List<AngularMotionPoint> = emptyList(),
    val oeps: List<OepResult> = emptyList(),
)

class AngularMotionCalculationException(message: String, cause: Throwable? = null) : RuntimeException(message, cause)
