package com.ffii.fpsms.modules.productProcess.entity

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.JpaSpecificationExecutor
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import org.springframework.stereotype.Repository
import java.util.*
import java.time.LocalDate

interface JobOrderProcessAggregate {
    val jobOrderId: Long
    val maxDate: LocalDate?
    val minPriority: Int?
}

@Repository
interface ProductProcessRepository : JpaRepository<ProductProcess, Long>, JpaSpecificationExecutor<ProductProcess> {
    fun findByProductProcessCode(code: String): Optional<ProductProcess>
    fun findByJobOrder_Id(jobOrderId: Long): List<ProductProcess>
    fun findByProductProcessCodeStartingWith(prefix: String): List<ProductProcess>
    fun findTopByProductProcessCodeStartingWithOrderByProductProcessCodeDesc(prefix: String): ProductProcess?
    fun findByIdAndDeletedIsFalse(id: Long): Optional<ProductProcess>
    fun findAllByDeletedIsFalse(): List<ProductProcess>
    fun findByBom_Id(bomId: Long): List<ProductProcess>
    fun findAllByDeletedIsFalseAndDate(date: LocalDate): List<ProductProcess>
    fun findByJobOrder_IdInAndDeletedIsFalse(jobOrderIds: List<Long>): List<ProductProcess>
    fun findByJobOrder_IdInAndDeletedIsFalseOrderByDateDescProductionPriorityAsc(jobOrderIds: Collection<Long>): List<ProductProcess>

    @Query(
        """
        SELECT 
            p.jobOrder.id AS jobOrderId,
            MAX(p.date) AS maxDate,
            MIN(COALESCE(p.productionPriority, 2147483647)) AS minPriority
        FROM ProductProcess p
        WHERE p.deleted = false
          AND p.jobOrder IS NOT NULL
          AND COALESCE(p.jobOrder.isHidden, false) = false
          AND p.jobOrder.status <> com.ffii.fpsms.modules.jobOrder.enums.JobOrderStatus.PLANNING
          AND (:date IS NULL OR p.date = :date)
          AND (:itemCode IS NULL OR LOWER(COALESCE(p.item.code, '')) LIKE LOWER(CONCAT('%', :itemCode, '%')))
          AND (:jobOrderCode IS NULL OR LOWER(COALESCE(p.jobOrder.code, '')) LIKE LOWER(CONCAT('%', :jobOrderCode, '%')))
          AND (:bomType IS NULL OR LOWER(COALESCE(p.bom.type, '')) = LOWER(:bomType))
          AND (:useBomIds = false OR p.bom.id IN :bomIds)
        GROUP BY p.jobOrder.id
        ORDER BY MAX(p.date) DESC, MIN(COALESCE(p.productionPriority, 2147483647)) ASC
        """
    )
    fun findCandidateJobOrderAggregates(
        @Param("date") date: LocalDate?,
        @Param("itemCode") itemCode: String?,
        @Param("jobOrderCode") jobOrderCode: String?,
        @Param("bomType") bomType: String?,
        @Param("useBomIds") useBomIds: Boolean,
        @Param("bomIds") bomIds: Collection<Long>,
    ): List<JobOrderProcessAggregate>
}