package com.ffii.fpsms.modules.pickOrder.entity



import com.ffii.core.support.AbstractRepository

import org.springframework.data.jpa.repository.Query

import org.springframework.data.repository.query.Param

import org.springframework.stereotype.Repository



@Repository

interface TruckLaneScheduleLineRepository : AbstractRepository<TruckLaneScheduleLine, Long> {

    fun findAllBySchedule_IdAndDeletedFalseOrderByIdAsc(scheduleId: Long): List<TruckLaneScheduleLine>

    fun findAllBySchedule_IdInAndDeletedFalseOrderBySchedule_IdAscIdAsc(
        scheduleIds: Collection<Long>,
    ): List<TruckLaneScheduleLine>



    @Query(

        """

        SELECT DISTINCT l.truckRowId FROM TruckLaneScheduleLine l

        JOIN l.schedule s

        WHERE l.deleted = false AND s.deleted = false

          AND l.lineStatus = :pendingLine

          AND s.status IN :openStatuses

        """,

    )

    fun findPendingTruckRowIds(

        @Param("pendingLine") pendingLine: TruckLaneScheduleLineStatus,

        @Param("openStatuses") openStatuses: Collection<TruckLaneScheduleStatus>,

    ): List<Long>

    /** 鎖定中的 truck rows：APPLYING 排程，或 executeAt 已進入鎖定時間窗的 PENDING 排程。 */
    @Query(
        """
        SELECT DISTINCT l.truckRowId FROM TruckLaneScheduleLine l
        JOIN l.schedule s
        WHERE l.deleted = false AND s.deleted = false
          AND l.lineStatus = :pendingLine
          AND s.status IN :openStatuses
          AND (s.status = :applyingStatus OR s.executeAt <= :lockBefore)
        """,
    )
    fun findLockingPendingTruckRowIds(
        @Param("pendingLine") pendingLine: TruckLaneScheduleLineStatus,
        @Param("openStatuses") openStatuses: Collection<TruckLaneScheduleStatus>,
        @Param("applyingStatus") applyingStatus: TruckLaneScheduleStatus,
        @Param("lockBefore") lockBefore: java.time.LocalDateTime,
    ): List<Long>

    @Query(
        """
        SELECT COUNT(l) FROM TruckLaneScheduleLine l
        JOIN l.schedule s
        WHERE l.deleted = false AND s.deleted = false
          AND l.truckRowId = :truckRowId
          AND l.lineStatus = :pendingLine
          AND s.status IN :openScheduleStatuses
          AND (s.status = :applyingStatus OR s.executeAt <= :lockBefore)
          AND (:excludeScheduleId IS NULL OR s.id <> :excludeScheduleId)
        """,
    )
    fun countLockingOpenPendingForTruckRow(
        @Param("truckRowId") truckRowId: Long,
        @Param("pendingLine") pendingLine: TruckLaneScheduleLineStatus,
        @Param("openScheduleStatuses") openScheduleStatuses: Collection<TruckLaneScheduleStatus>,
        @Param("applyingStatus") applyingStatus: TruckLaneScheduleStatus,
        @Param("lockBefore") lockBefore: java.time.LocalDateTime,
        @Param("excludeScheduleId") excludeScheduleId: Long?,
    ): Long

    @Query(
        """
        SELECT COUNT(l) > 0 FROM TruckLaneScheduleLine l
        JOIN l.schedule s
        WHERE l.deleted = false AND s.deleted = false
          AND s.status IN :openScheduleStatuses
          AND l.lineStatus = :pendingLine
          AND l.toTruckLanceCode = :laneCode
          AND l.toStoreId = :storeId
          AND (s.status = :applyingStatus OR s.executeAt <= :lockBefore)
          AND (:excludeScheduleId IS NULL OR s.id <> :excludeScheduleId)
        """,
    )
    fun existsLockingOpenScheduleForLaneBucket(
        @Param("laneCode") laneCode: String,
        @Param("storeId") storeId: String,
        @Param("pendingLine") pendingLine: TruckLaneScheduleLineStatus,
        @Param("openScheduleStatuses") openScheduleStatuses: Collection<TruckLaneScheduleStatus>,
        @Param("applyingStatus") applyingStatus: TruckLaneScheduleStatus,
        @Param("lockBefore") lockBefore: java.time.LocalDateTime,
        @Param("excludeScheduleId") excludeScheduleId: Long?,
    ): Boolean

    /** 其他開放排程中，對同店鋪 + 同目標車線桶的 PENDING CREATE 行數。 */
    @Query(
        """
        SELECT COUNT(l) FROM TruckLaneScheduleLine l
        JOIN l.schedule s
        WHERE l.deleted = false AND s.deleted = false
          AND l.lineStatus = :pendingLine
          AND s.status IN :openScheduleStatuses
          AND l.lineAction = :createAction
          AND l.shopId = :shopId
          AND l.toTruckLanceCode = :laneCode
          AND l.toStoreId = :storeId
        """,
    )
    fun countOpenPendingCreateForShopInBucket(
        @Param("shopId") shopId: Long,
        @Param("laneCode") laneCode: String,
        @Param("storeId") storeId: String,
        @Param("createAction") createAction: TruckLaneScheduleLineAction,
        @Param("pendingLine") pendingLine: TruckLaneScheduleLineStatus,
        @Param("openScheduleStatuses") openScheduleStatuses: Collection<TruckLaneScheduleStatus>,
    ): Long



    @Query(
        """
        SELECT COUNT(l) FROM TruckLaneScheduleLine l
        JOIN l.schedule s
        WHERE l.deleted = false AND s.deleted = false
          AND l.truckRowId = :truckRowId
          AND l.lineStatus = :pendingLine
          AND s.status IN :openScheduleStatuses
          AND (:excludeScheduleId IS NULL OR s.id <> :excludeScheduleId)
        """,
    )
    fun countOpenPendingForTruckRow(
        @Param("truckRowId") truckRowId: Long,
        @Param("pendingLine") pendingLine: TruckLaneScheduleLineStatus,
        @Param("openScheduleStatuses") openScheduleStatuses: Collection<TruckLaneScheduleStatus>,
        @Param("excludeScheduleId") excludeScheduleId: Long?,
    ): Long

    @Query(
        """
        SELECT COUNT(l) > 0 FROM TruckLaneScheduleLine l
        JOIN l.schedule s
        WHERE l.deleted = false AND s.deleted = false
          AND s.status IN :openScheduleStatuses
          AND l.lineStatus = :pendingLine
          AND l.toTruckLanceCode = :laneCode
          AND l.toStoreId = :storeId
          AND (:excludeScheduleId IS NULL OR s.id <> :excludeScheduleId)
        """,
    )
    fun existsOpenScheduleForLaneBucket(
        @Param("laneCode") laneCode: String,
        @Param("storeId") storeId: String,
        @Param("pendingLine") pendingLine: TruckLaneScheduleLineStatus,
        @Param("openScheduleStatuses") openScheduleStatuses: Collection<TruckLaneScheduleStatus>,
        @Param("excludeScheduleId") excludeScheduleId: Long?,
    ): Boolean

}

