package com.ffii.fpsms.modules.deliveryOrder.entity

import com.ffii.core.support.AbstractRepository

import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Repository
import java.io.Serializable
import java.time.LocalDateTime
import com.ffii.fpsms.modules.deliveryOrder.web.models.*
import com.ffii.fpsms.modules.deliveryOrder.entity.models.*
@Repository
interface DeliveryOrderRepository : AbstractRepository<DeliveryOrder, Long> {
    fun existsByCodeAndDeletedIsFalse(code: String): Boolean

        @Query("""
        select d from DeliveryOrder d
        where d.deleted = false
        and (:code is null or d.code like concat('%', :code, '%'))
        and (:shopName is null or d.shop.name like concat('%', :shopName, '%'))
        and (:status is null or d.status = :status)
        and (:orderFrom is null or d.orderDate >= :orderFrom)
        and (:orderTo is null or d.orderDate < :orderTo)
        and (:etaFrom is null or d.estimatedArrivalDate >= :etaFrom)
        and (:etaTo is null or d.estimatedArrivalDate < :etaTo)
    """)
    fun search(
        @Param("code") code: String?,
        @Param("shopName") shopName: String?,
        @Param("status") status: String?,
        @Param("orderFrom") orderFrom: LocalDateTime?,
        @Param("orderTo") orderTo: LocalDateTime?,
        @Param("etaFrom") etaFrom: LocalDateTime?,
        @Param("etaTo") etaTo: LocalDateTime?,
        pageable: Pageable
    ): Page<DeliveryOrder>

    fun findTopByM18DataLogIdAndDeletedIsFalseOrderByModifiedDesc(m18datalogId: Serializable): DeliveryOrder?

    fun findTopByM18DataLogIdOrderByModifiedDesc(m18datalogId: Serializable): DeliveryOrder?

    fun findDeliveryOrderInfoByDeletedIsFalse(): List<DeliveryOrderInfo>

    fun findByIdAndDeletedIsFalse(id: Serializable): DeliveryOrder?

    fun findAllByCodeContainsAndDeletedIsFalse(code: String?): List<DeliveryOrderInfo>

    fun findAllByShopNameContainsAndDeletedIsFalse(shopName: String?): List<DeliveryOrderInfo>

    fun findAllByStatusAndDeletedIsFalse(status: DeliveryOrderStatus?): List<DeliveryOrderInfo>

    fun findByOrderDateBetweenAndDeletedIsFalse(startDate: LocalDateTime?, endDate: LocalDateTime?) : List<DeliveryOrderInfo>

    fun findDeliveryOrderInfoById(id: Long): List<DeliveryOrderInfo>

    //GET FULL LIST
    fun findAllBy() : List<DeliveryOrderInfo>;

    //SEARCH ALL
    fun findAllByCodeContainsAndShopNameContainsAndStatusAndOrderDateBetweenAndEstimatedArrivalDateBetweenAndDeletedIsFalse(code: String?, shopName: String?, status: DeliveryOrderStatus?, orderStartDate: LocalDateTime?, orderEndDate: LocalDateTime?, estArrStartDate: LocalDateTime?, estArrEndDate: LocalDateTime?) : List<DeliveryOrderInfo>;
    //SEARCH WITHOUT STATUS
    fun findAllByCodeContainsAndShopNameContainsAndOrderDateBetweenAndEstimatedArrivalDateBetweenAndDeletedIsFalse(code: String?, shopName: String?, orderStartDate: LocalDateTime?, orderEndDate: LocalDateTime?, estArrStartDate: LocalDateTime?, estArrEndDate: LocalDateTime?) : List<DeliveryOrderInfo>;

    //SEARCH WITHOUT EST ARR DATE
    fun findAllByCodeContainsAndShopNameContainsAndStatusAndOrderDateBetweenAndDeletedIsFalse(code: String?, shopName: String?, status: DeliveryOrderStatus?, orderStartDate: LocalDateTime?, orderEndDate: LocalDateTime?) : List<DeliveryOrderInfo>;
    //SEARCH WITHOUT EST ARR DATE + STATUS
    fun findAllByCodeContainsAndShopNameContainsAndOrderDateBetweenAndDeletedIsFalse(code: String?, shopName: String?, orderStartDate: LocalDateTime?, orderEndDate: LocalDateTime?) : List<DeliveryOrderInfo>;

    //SEARCH WITHOUT ORDER DATE
    fun findAllByCodeContainsAndShopNameContainsAndStatusAndEstimatedArrivalDateBetweenAndDeletedIsFalse(code: String?, shopName: String?, status: DeliveryOrderStatus?, estArrStartDate: LocalDateTime?, estArrEndDate: LocalDateTime?) : List<DeliveryOrderInfo>;
    //SEARCH WITHOUT ORDER DATE + STATUS
    fun findAllByCodeContainsAndShopNameContainsAndEstimatedArrivalDateBetweenAndDeletedIsFalse(code: String?, shopName: String?, estArrStartDate: LocalDateTime?, estArrEndDate: LocalDateTime?): List<DeliveryOrderInfo>;

    //SEARCH WITHOUT DATE + STATUS
    fun findAllByCodeContainsAndShopNameContainsAndDeletedIsFalse(code: String?, shopName: String?) : List<DeliveryOrderInfo>;

    //SEARCH WITHOUT DATE
    fun findAllByCodeContainsAndShopNameContainsAndStatusAndDeletedIsFalse(code: String?, shopName: String?, staus: DeliveryOrderStatus?) : List<DeliveryOrderInfo>;

    fun findDeliveryOrderInfoByCodeContainsAndShopNameContainsAndDeletedIsFalseOrderByIdDesc(code: String, shopName: String, pageable: Pageable): Page<DeliveryOrderInfo>



    @Query("""
    select d from DeliveryOrder d
    where d.deleted = false
    and (:code is null or d.code like concat('%', :code, '%'))
    and (:shopName is null or d.shop.name like concat('%', :shopName, '%'))
    and (:status is null or d.status = :status)
    and (:estimatedArrivalDate is null or DATE(d.estimatedArrivalDate) = DATE(:estimatedArrivalDate))
    order by d.id desc
""")
fun searchDoLite(
    @Param("code") code: String?,
    @Param("shopName") shopName: String?,
    @Param("status") status: String?,
    @Param("estimatedArrivalDate") estimatedArrivalDate: LocalDateTime?,
    pageable: Pageable
): Page<DeliveryOrderInfoLite> 


@Query("""
    select distinct d from DeliveryOrder d
    where d.deleted = false
      and (:code is null or d.code like concat('%', :code, '%'))
      and (:shopName is null or d.shop.name like concat('%', :shopName, '%'))
      and (:status is null or d.status = :status)
      and (:etaStart is null or d.estimatedArrivalDate >= :etaStart)
      and (:etaEnd   is null or d.estimatedArrivalDate <  :etaEnd)
      and (:isExtra is null or d.isExtra = :isExtra)
    order by d.id desc
""")
fun searchDoLitePage(
    @Param("code") code: String?,
    @Param("shopName") shopName: String?,
    @Param("status") status: DeliveryOrderStatus?,
    @Param("etaStart") etaStart: LocalDateTime?,
    @Param("etaEnd") etaEnd: LocalDateTime?,
    @Param("isExtra") isExtra: Boolean?,
    pageable: Pageable
): Page<DeliveryOrderInfoLite>

/**
 * 與 [searchDoLitePage] 相同條件，但僅包含指定供應商代碼；分頁須在此集合上計算，否則總筆數與每頁筆數會不一致。
 */
@Query(
    """
    select distinct d from DeliveryOrder d
    where d.deleted = false
      and (:code is null or d.code like concat('%', :code, '%'))
      and (:shopName is null or d.shop.name like concat('%', :shopName, '%'))
      and (:status is null or d.status = :status)
      and (:etaStart is null or d.estimatedArrivalDate >= :etaStart)
      and (:etaEnd   is null or d.estimatedArrivalDate <  :etaEnd)
      and (:isExtra is null or d.isExtra = :isExtra)
      and d.supplier is not null
      and d.supplier.code in :allowedSupplierCodes
    order by d.id desc
"""
)
fun searchDoLitePageWithSupplierCodes(
    @Param("code") code: String?,
    @Param("shopName") shopName: String?,
    @Param("status") status: DeliveryOrderStatus?,
    @Param("etaStart") etaStart: LocalDateTime?,
    @Param("etaEnd") etaEnd: LocalDateTime?,
    @Param("isExtra") isExtra: Boolean?,
    @Param("allowedSupplierCodes") allowedSupplierCodes: List<String>,
    pageable: Pageable,
): Page<DeliveryOrderInfoLite>
}
