package space.nstart.pcp_tgu_service.repository

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_tgu_service.entity.AcceptedPlanSlotsUpdateJobEntity
import java.time.LocalDateTime
import java.util.UUID

/** Доступ к jobs запуска BPMN updateAcceptedPlanSlots. */
interface AcceptedPlanSlotsUpdateJobRepository : JpaRepository<AcceptedPlanSlotsUpdateJobEntity, UUID> {
    /** Атомарно создаёт job один раз на planId. */
    @Modifying
    @Query(
        value = """
            INSERT INTO accepted_plan_slots_update_job(
                plan_id,
                status,
                created_at,
                updated_at
            )
            VALUES (
                :planId,
                'PENDING',
                :now,
                :now
            )
            ON CONFLICT (plan_id) DO NOTHING
        """,
        nativeQuery = true
    )
    fun insertPendingIfAbsent(
        @Param("planId") planId: UUID,
        @Param("now") now: LocalDateTime
    ): Int

    /**
     * Claim'ит jobs через row lock.
     *
     * RUNNING job можно подобрать только после истечения lease и только если processInstanceKey ещё не сохранён.
     */
    @Query(
        value = """
            SELECT *
            FROM accepted_plan_slots_update_job
            WHERE status = 'PENDING'
               OR (
                    status = 'RUNNING'
                    AND locked_until < :now
                    AND process_instance_key IS NULL
               )
            ORDER BY created_at
            LIMIT :limit
            FOR UPDATE SKIP LOCKED
        """,
        nativeQuery = true
    )
    fun findClaimableForUpdate(
        @Param("now") now: LocalDateTime,
        @Param("limit") limit: Int
    ): List<AcceptedPlanSlotsUpdateJobEntity>
}
