package space.nstart.pcp.slots_service.repository

import jakarta.persistence.EntityManager
import jakarta.persistence.PersistenceContext
import jakarta.transaction.Transactional
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Modifying
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import space.nstart.pcp.slots_service.entity.SlotEntity
import java.time.LocalDateTime
import java.util.Optional

interface SlotRepository: JpaRepository<SlotEntity, Long>, SlotRepositoryCustom {
    interface SlotCalculationSummaryProjection {
        val satelliteId: Long
        val slotCount: Long
        val minTime: LocalDateTime?
        val maxTime: LocalDateTime?
        val minRevolution: Long?
        val maxRevolution: Long?
    }


    @Modifying
    @Transactional
    @Query("DELETE FROM  slot WHERE satellite_id =:sat", nativeQuery = true)
    fun deleteBySatId(@Param("sat") sat : Long) : Int

    fun findBySatelliteId(id : Long) : List<SlotEntity>

    fun countBySatelliteId(id: Long): Long

    fun findBySatelliteIdAndRevolutionIn(id : Long, revs : Iterable<Long>) : List<SlotEntity>

    fun findBySatelliteIdAndSlotNum(id : Long, num : Long) : Optional<SlotEntity>

    fun findBySatelliteIdAndTkAfterAndTnBeforeOrderByTnAscTkAscSatelliteIdAscSlotNumAsc(
        satelliteId: Long,
        timeStart: java.time.LocalDateTime,
        timeStop: java.time.LocalDateTime
    ): List<SlotEntity>

    @Query(
        """
        SELECT
            CAST(:satelliteId AS BIGINT) AS "satelliteId",
            CASE
                WHEN EXISTS (SELECT 1 FROM slot WHERE satellite_id = :satelliteId)
                    THEN CAST(1 AS BIGINT)
                ELSE CAST(0 AS BIGINT)
            END AS "slotCount",
            (SELECT tn FROM slot WHERE satellite_id = :satelliteId ORDER BY tn ASC LIMIT 1) AS "minTime",
            (SELECT tk FROM slot WHERE satellite_id = :satelliteId ORDER BY tk DESC LIMIT 1) AS "maxTime",
            (SELECT revolution FROM slot WHERE satellite_id = :satelliteId ORDER BY revolution ASC LIMIT 1) AS "minRevolution",
            (SELECT revolution FROM slot WHERE satellite_id = :satelliteId ORDER BY revolution DESC LIMIT 1) AS "maxRevolution"
        """,
        nativeQuery = true
    )
    fun slotCalculationSummary(@Param("satelliteId") satelliteId: Long): SlotCalculationSummaryProjection

    @Query(value = "SELECT * FROM slot WHERE ST_Intersects( ST_GeomFromText(:polygon, 4326), contour_geom)", nativeQuery = true)
    fun findAllByWKT(@Param("polygon") polygonWkt: String): List<SlotEntity>

    @Query(value = "SELECT * FROM slot WHERE satellite_id=:id AND ST_Intersects( ST_GeomFromText(:polygon, 4326), contour_geom)", nativeQuery = true)
    fun findByWKTAndSatId(@Param("polygon") polygonWkt: String, @Param("id") id : Long): List<SlotEntity>

    @Query(
        value = "SELECT * FROM slot WHERE satellite_id IN (:ids) AND ST_Intersects(ST_GeomFromText(:polygon, 4326), contour_geom)",
        nativeQuery = true
    )
    fun findByWKTAndSatelliteIdIn(@Param("polygon") polygonWkt: String, @Param("ids") ids: Collection<Long>): List<SlotEntity>

}
