package space.nstart.pcp.slots_service.entity

import jakarta.persistence.*
import org.hibernate.annotations.Fetch
import org.hibernate.annotations.FetchMode
import space.nstart.pcp.pcp_types_lib.dto.ballistics.RevolutionSign
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.SlotStatus
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.SlotDTO
import space.nstart.pcp.pcp_types_lib.dto.requests.slots.SlotHolderDTO
import space.nstart.pcp.pcp_types_lib.utils.wkt.WKTParser
import space.nstart.pcp.slots_service.model.Mar
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes
import java.time.LocalDateTime


@Entity
@Table(name = "slot")
class SlotEntity(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val slotId : Long? = null,
    @Column(nullable = false)
    val slotNum : Long = 0,
    @Column(nullable = false)
    var cycle : Long = 0,
    @Column(nullable = false)
    val satelliteId : Long = 0,
    @Column(nullable = false)
    val coveringType : Int = 0,
    @Column(nullable = false)
    var tn : LocalDateTime = UtcDateTimes.now(),
    @Column(nullable = false)
    var tk : LocalDateTime = UtcDateTimes.now(),
    val roll : Double = 0.0,
    @Column(name = "contour_wkt", columnDefinition = "TEXT", nullable = false)
    val contour : String = "",
    @Column(nullable = false)
    var revolution : Long = 0,
    @Column(name = "revolution_sign", columnDefinition = "VARCHAR", nullable = false)
    val revolutionSign: String = RevolutionSign.ASC.toString(),
    @OneToMany(
        fetch = FetchType.LAZY,
        mappedBy = "slot",
        cascade = [CascadeType.PERSIST, CascadeType.MERGE],
        orphanRemoval = true
    )
    @Fetch(FetchMode.SUBSELECT)
    val modes: MutableList<BookedSlotEntity>? = null,

    val latitude : Double = 0.0,
    val longitude : Double = 0.0,
) {

    constructor(mar : Mar, slotNum : Long, type : Int) : this(
        slotNum = slotNum,
        cycle = 1,
        satelliteId = mar.sat,
        tn = mar.tn,
        tk = mar.tk,
        roll = mar.roll,
        contour = mar.contour,
        revolution = mar.vit,
        revolutionSign = mar.revolutionSign.toString(),
        coveringType = type
    )

    fun toMar(parser : WKTParser) = Mar(
        sat = satelliteId,
        tn = tn,
        tk = tk,
        roll = roll,
        contour = contour,
        poly = parser.parseWKT(contour),
        vit = revolution,
        revolutionSign = RevolutionSign.valueOf(revolutionSign),
        slotNum = slotNum
    )

    fun toDTO() = SlotDTO(
        cycle,
        satelliteId,
        tn,
        tk,
        roll,
        contour,
        revolution,
        RevolutionSign.valueOf(revolutionSign),
        slotNum,
        SlotStatus.AVAILABLE,
        latitude,
        longitude
    )

    fun toDTO(status : SlotStatus) = SlotDTO(
        cycle,
        satelliteId,
        tn,
        tk,
        roll,
        contour,
        revolution,
        RevolutionSign.valueOf(revolutionSign),
        slotNum,
        state = status,
        latitude,
        longitude
    )

    fun toDTO(booked : Boolean, band : Boolean, holders : List<SlotHolderDTO>? = null) = SlotDTO(
        cycle,
        satelliteId,
        tn,
        tk,
        roll,
        contour,
        revolution,
        RevolutionSign.valueOf(revolutionSign),
        slotNum,
        state = if (booked) SlotStatus.BOOKED else if (band) SlotStatus.BUSY else SlotStatus.AVAILABLE,
        latitude,
        longitude,
        holders = holders
    )
}
