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

import com.ffii.core.support.AbstractRepository
import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderInfo
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderType
import com.ffii.fpsms.modules.pickOrder.web.models.SearchPickOrderRequest
import com.ffii.fpsms.modules.jobOrder.enums.JobOrderStatus
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import org.springframework.stereotype.Repository
import com.ffii.fpsms.modules.user.entity.User
import java.io.Serializable
import java.time.LocalDateTime
import org.springframework.data.jpa.repository.Modifying
@Repository
interface PickOrderRepository : AbstractRepository<PickOrder, Long> {
    fun findPickOrderInfoByDeletedIsFalse(): List<PickOrderInfo>

    @Query(
        """
            select po from PickOrder po
            where (lower(:code) = 'all' or lower(po.code) like concat('%',lower(:code),'%')) 
            and (:targetDateFrom is null or po.targetDate >= :targetDateFrom) 
            and (:targetDateTo is null or po.targetDate <= :targetDateTo)
            and (lower(:type) = 'all' or lower(po.type) like concat('%',lower(:type),'%'))
            and (lower(:status) = 'all' or lower(po.status) like concat('%',lower(:status),'%'))
            and (lower(:itemName) = 'all' or exists (
                    select 1 from PickOrderLine pol
                    where pol.pickOrder = po
                    and (lower(:itemName) = 'all' or lower(pol.item.name) like concat('%',lower(:itemName),'%'))
                )
            )
            and (:assignTo is null or (po.assignTo is not null and po.assignTo.id = :assignTo))
            and po.consoCode = null
            and po.deleted = false
        """
    )
    fun findPickOrderInfoByConditionsAndPageable(
        code: String,
        targetDateFrom: LocalDateTime?,
        targetDateTo: LocalDateTime?,
        type: String,
        status: String,
        itemName: String,
        assignTo: Long?,
        pageable: Pageable,
    ): Page<PickOrderInfo>

    @Query(
        """
        SELECT po.consoCode FROM pick_order po
        WHERE po.consoCode LIKE CONCAT(:prefix, '%')
        ORDER BY CAST(SUBSTRING_INDEX(po.consoCode, '-', -1) AS UNSIGNED) DESC
        LIMIT 1
        """,
        nativeQuery = true,
    )
    fun findLatestConsoCodeByPrefix(@Param("prefix") prefix: String): String?

    @Query(
        """
        SELECT po.code FROM pick_order po
        WHERE po.code LIKE CONCAT(:prefix, '%')
        ORDER BY CAST(SUBSTRING_INDEX(po.code, '-', -1) AS UNSIGNED) DESC
        LIMIT 1
        """,
        nativeQuery = true,
    )
    fun findLatestCodeByPrefix(@Param("prefix") prefix: String): String?
    fun findAllByIdInAndStatus(id: List<Serializable>, status: PickOrderStatus): List<PickOrder>

    fun findAllByIdInAndConsoCodeIsNullAndStatus(id: List<Serializable>, status: PickOrderStatus): List<PickOrder>

    fun findPickOrderInfoByIdIn(id: List<Serializable>): List<PickOrderInfo>

    fun findAllByConsoCode(consoCode: String): List<PickOrder>

    fun findAllByConsoCodeAndStatus(consoCode: String, status: PickOrderStatus): List<PickOrder>

    fun findAllByIdIn(id: List<Serializable>): List<PickOrder>

    @Query("SELECT p FROM PickOrder p WHERE p.assignTo = :assignTo AND p.status IN :statuses AND p.deleted = false")
    fun findAllByAssignToAndStatusIn(@Param("assignTo") assignTo: User, @Param("statuses") statuses: List<PickOrderStatus>): List<PickOrder>
    
    @Query("SELECT p FROM PickOrder p WHERE p.status = :status AND p.deleted = false ORDER BY p.targetDate ASC")
    fun findAllByStatusAndDeletedFalse(@Param("status") status: PickOrderStatus): List<PickOrder>
    @Query("SELECT p FROM PickOrder p WHERE p.assignTo.id = :assignToId AND p.status IN :statuses AND p.deleted = false")
    fun findAllByAssignToIdAndStatusIn(@Param("assignToId") assignToId: Long, @Param("statuses") statuses: List<PickOrderStatus>): List<PickOrder>

    @Query("SELECT p FROM PickOrder p WHERE p.deliveryOrder.id = :deliveryOrderId AND p.deleted = false")
    fun findByDeliveryOrderId(@Param("deliveryOrderId") deliveryOrderId: Long): List<PickOrder>

    // 在 PickOrderRepository 中添加：
fun findAllByStatusAndAssignToIsNullAndDeletedFalse(status: PickOrderStatus): List<PickOrder>
//fun findAllByJoid(jobOrderId: Long): List<PickOrder>
fun findAllByJobOrder_Id(jobOrderId: Long): List<PickOrder>
fun findAllByJobOrder_IdInAndDeletedFalseOrderByJobOrder_IdAscCreatedDesc(jobOrderIds: Collection<Long>): List<PickOrder>
fun findTopByJobOrder_IdOrderByCreatedDesc(jobOrderId: Long): PickOrder?
fun findAllByStatusIn(statuses: List<PickOrderStatus>): List<PickOrder>
fun findByCodeAndDeletedFalse(@Param("code") code: String): PickOrder?

@Query(
    """
    SELECT po FROM PickOrder po
    WHERE po.status = :status
    AND po.deleted = false
    AND po.jobOrder IS NOT NULL
    AND po.jobOrder.planEnd IS NOT NULL
    AND po.jobOrder.planEnd >= :planEndFrom
    AND po.jobOrder.planEnd < :planEndToExclusive
    """
)
fun findAllCompletedWithJobOrderPlanEndOnDay(
    @Param("status") status: PickOrderStatus,
    @Param("planEndFrom") planEndFrom: LocalDateTime,
    @Param("planEndToExclusive") planEndToExclusive: LocalDateTime,
): List<PickOrder>

@Query(
    """
    SELECT po FROM PickOrder po
    WHERE po.status = :status
    AND po.deleted = false
    AND po.jobOrder IS NOT NULL
    AND po.jobOrder.planStart IS NOT NULL
    AND po.jobOrder.planStart >= :planStartFrom
    AND po.jobOrder.planStart < :planStartToExclusive
    """
)
fun findAllCompletedWithJobOrderPlanStartOnDay(
    @Param("status") status: PickOrderStatus,
    @Param("planStartFrom") planStartFrom: LocalDateTime,
    @Param("planStartToExclusive") planStartToExclusive: LocalDateTime,
): List<PickOrder>

@Query(
    """
    SELECT po FROM PickOrder po
    WHERE po.status = :status
    AND po.deleted = false
    AND po.jobOrder IS NOT NULL
    AND po.jobOrder.planStart IS NOT NULL
    AND po.jobOrder.planStart >= :planStartFrom
    AND po.jobOrder.planStart < :planStartToExclusive
    AND (
        po.plasticBoxCartonQty2f IS NOT NULL
        OR po.plasticBoxCartonQty3f IS NOT NULL
        OR po.plasticBoxCartonQty4f IS NOT NULL
    )
    """
)
fun findCompletedWithPlasticBoxCartonQtyInPlanStartRange(
    @Param("status") status: PickOrderStatus,
    @Param("planStartFrom") planStartFrom: LocalDateTime,
    @Param("planStartToExclusive") planStartToExclusive: LocalDateTime,
): List<PickOrder>


@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query(
    value = """
        UPDATE fpsmsdb.pick_order
        SET assignTo = :userId,
            status = :status,
            modified = :modified,
            modifiedBy = :modifiedBy
        WHERE deliveryOrderPickOrderId = :dopoId
          AND deleted = 0
    """,
    nativeQuery = true
)
fun bulkAssignWorkbenchTicket(
    @Param("dopoId") dopoId: Long,
    @Param("userId") userId: Long,
    @Param("status") status: String,   // 传 "released"
    @Param("modified") modified: LocalDateTime,
    @Param("modifiedBy") modifiedBy: String,
): Int


@Query(
    value = """
        SELECT id
        FROM fpsmsdb.pick_order
        WHERE deliveryOrderPickOrderId = :dopoId
          AND deleted = 0
    """,
    nativeQuery = true
)
fun findIdsByDeliveryOrderPickOrderId(@Param("dopoId") dopoId: Long): List<Long>

@Query("""
SELECT p.id
FROM PickOrder p
WHERE p.deleted = false
  AND p.assignTo.id = :userId
  AND p.status = :status
  AND (p.type IS NULL OR p.type NOT IN :excludedTypes)
""")
fun findReleasedIdsForPickExecution(
    @Param("userId") userId: Long,
    @Param("status") status: PickOrderStatus,
    @Param("excludedTypes") excludedTypes: List<PickOrderType>,
): List<Long>

@Query("""
SELECT po
FROM PickOrder po
JOIN po.jobOrder jo
WHERE po.deleted = false
  AND po.jobOrder IS NOT NULL
  AND (jo.isHidden = false OR jo.isHidden IS NULL)
  AND jo.planStart >= :from
  AND jo.planStart < :toExclusive
  AND (:status IS NULL OR po.status = :status)
""")
fun findByJobOrderPlanStartOnDayAndOptionalStatus(
    @Param("from") from: LocalDateTime,
    @Param("toExclusive") toExclusive: LocalDateTime,
    @Param("status") status: PickOrderStatus?,
): List<PickOrder>

@Query(
    """
    SELECT DISTINCT po
    FROM PickOrder po
    JOIN FETCH po.jobOrder jo
    LEFT JOIN FETCH jo.bom bom
    LEFT JOIN FETCH bom.item item
    WHERE po.status = :status
      AND po.deleted = false
      AND po.jobOrder IS NOT NULL
      AND (jo.isHidden = false OR jo.isHidden IS NULL)
      AND jo.status <> :completedStatus
    """
)
fun findAllReleasedJoWorkbenchPickOrders(
    @Param("status") status: PickOrderStatus,
    @Param("completedStatus") completedStatus: JobOrderStatus,
): List<PickOrder>

@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query(
    value = """
        UPDATE fpsmsdb.pick_order
        SET submittedLines = COALESCE(submittedLines, 0) + 1,
            modified = CURRENT_TIMESTAMP
        WHERE id = :pickOrderId
          AND deleted = 0
    """,
    nativeQuery = true,
)
fun incrementSubmittedLines(@Param("pickOrderId") pickOrderId: Long): Int
}