package space.nstart.pcp.pcp_request_service.entity

import space.nstart.pcp.pcp_request_service.utils.UtcDateTimes
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.EnumType
import jakarta.persistence.Enumerated
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Table
import space.nstart.pcp.pcp_types_lib.dto.ballistics.InitialConditionsDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.MovementModel
import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
import java.time.LocalDateTime

@Entity
@Table(name = "satellite_initial_conditions")
class SatelliteInitialConditionEntity(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "satellite_initial_condition_id")
    val id: Long? = null,
    @Column(name = "satellite_id", nullable = false)
    val satelliteId: Long = 0,
    @Enumerated(EnumType.STRING)
    @Column(name = "movement_model", nullable = false)
    val movementModel: MovementModel = MovementModel.FOTO,
    @Column(name = "orb_time", nullable = false)
    val orbTime: LocalDateTime = UtcDateTimes.now(),
    @Column(name = "orb_revolution", nullable = false)
    val orbRevolution: Long = 0,
    @Column(nullable = false)
    val x: Double = 0.0,
    @Column(nullable = false)
    val y: Double = 0.0,
    @Column(nullable = false)
    val z: Double = 0.0,
    @Column(nullable = false)
    val vx: Double = 0.0,
    @Column(nullable = false)
    val vy: Double = 0.0,
    @Column(nullable = false)
    val vz: Double = 0.0,
    @Column(name = "s_ball", nullable = false)
    val sBall: Double = 0.0,
    @Column(nullable = false)
    val f81: Double = 147.8,
    @Column(name = "received_at", nullable = false)
    val receivedAt: LocalDateTime = UtcDateTimes.now(),
    @Column(name = "calculated_at")
    var calculatedAt: LocalDateTime? = null,
    @Column(name = "last_calculated", nullable = false)
    var lastCalculated: Boolean = false
) {
    constructor(request: SatelliteICDTO, receivedAt: LocalDateTime = UtcDateTimes.now()) : this(
        satelliteId = request.satelliteId,
        movementModel = request.movementModel,
        orbTime = request.ic.orbPoint.time,
        orbRevolution = request.ic.orbPoint.revolution,
        x = request.ic.orbPoint.x,
        y = request.ic.orbPoint.y,
        z = request.ic.orbPoint.z,
        vx = request.ic.orbPoint.vx,
        vy = request.ic.orbPoint.vy,
        vz = request.ic.orbPoint.vz,
        sBall = request.ic.sBall,
        f81 = request.ic.f81,
        receivedAt = receivedAt
    )

    fun markLastCalculated(calculatedAt: LocalDateTime = UtcDateTimes.now()) {
        this.calculatedAt = calculatedAt
        this.lastCalculated = true
    }

    fun toDto() = SatelliteICDTO(
        satelliteId = satelliteId,
        movementModel = movementModel,
        ic = InitialConditionsDTO(
            orbPoint = OrbPointDTO(
                time = orbTime,
                revolution = orbRevolution,
                vx = vx,
                vy = vy,
                vz = vz,
                x = x,
                y = y,
                z = z
            ),
            sBall = sBall,
            f81 = f81
        )
    )
}
