package com.ffii.fpsms.modules.purchaseOrder.entity

import com.ffii.core.support.AbstractRepository
import com.ffii.fpsms.modules.purchaseOrder.entity.projections.PurchaseOrderLineInfo
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus
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 java.io.Serializable

@Repository
interface PurchaseOrderLineRepository : AbstractRepository<PurchaseOrderLine, Long> {
    @Query(
        "SELECT pol FROM PurchaseOrderLine pol " +
            "LEFT JOIN FETCH pol.purchaseOrder po " +
            "LEFT JOIN FETCH po.supplier " +
            "JOIN FETCH pol.uom " +
            "LEFT JOIN FETCH pol.uomM18 " +
            "WHERE pol.deleted = false AND pol.item.id = :itemId AND pol.m18DataLog IS NOT NULL " +
            "ORDER BY pol.created DESC",
    )
    fun findLatestLinesForBomM18ByItemId(
        @Param("itemId") itemId: Long,
        pageable: Pageable,
    ): List<PurchaseOrderLine>

    /**
     * Latest PO (by header `purchase_order.created`) for a material item code: supplier `shop.m18Id` from `purchase_order.supplierId`.
     * Mirrors manual SQL: pol → items (code), po, shop on supplier, uom_conversion; order by po.created desc limit 1.
     */
    @Query(
        value =
            "SELECT sh.m18Id FROM purchase_order_line pol " +
                "LEFT JOIN items it ON pol.itemId = it.id " +
                "LEFT JOIN purchase_order po ON pol.purchaseOrderId = po.id " +
                "LEFT JOIN shop sh ON po.supplierId = sh.id " +
                "LEFT JOIN uom_conversion um ON pol.uomIdM18 = um.id " +
                "WHERE pol.deleted = false AND it.deleted = false AND it.code = :itemCode " +
                "ORDER BY po.created DESC LIMIT 1",
        nativeQuery = true,
    )
    fun findLatestPoSupplierM18IdByItemCodeNative(@Param("itemCode") itemCode: String): List<Long>

    fun findByM18DataLogIdAndDeletedIsFalse(m18datalogId: Serializable): PurchaseOrderLine?
    fun findAllPurchaseOrderLineInfoByPurchaseOrderIdAndDeletedIsFalse(purchaseOrderId: Long): List<PurchaseOrderLineInfo>
    fun findAllByPurchaseOrderIdAndDeletedIsFalse(purchaseOrderId: Long): List<PurchaseOrderLine>
    fun findAllByPurchaseOrderIdAndDeletedIsFalseAndM18DataLogIsNotNull(purchaseOrderId: Long): List<PurchaseOrderLine>
    fun findAllByPurchaseOrderIdAndStatusNotAndDeletedIsFalse(purchaseOrderId: Long, status: PurchaseOrderLineStatus): List<PurchaseOrderLine>
//    fun findAllByPurchaseOrderIdAndDeletedIsFalse(purchaseOrderId: Long): List<PurchaseOrderLine>
    //    fun find

    /**
     * M18 sync: resolve the local line by PO + M18 line id (m18_data_log.m18Id), not by latest log row id.
     * Newest id first so we attach the new sync to the canonical row when duplicates exist.
     */
    @Query(
        "SELECT pol FROM PurchaseOrderLine pol WHERE pol.deleted = false " +
            "AND pol.purchaseOrder.id = :purchaseOrderId AND pol.m18DataLog.m18Id = :m18LineId ORDER BY pol.id DESC"
    )
    fun findAllByPurchaseOrderIdAndM18LineIdOrderByIdDesc(
        @Param("purchaseOrderId") purchaseOrderId: Long,
        @Param("m18LineId") m18LineId: Long
    ): List<PurchaseOrderLine>

    @Query("SELECT pol FROM PurchaseOrderLine pol WHERE pol.deleted = false AND pol.item IS NOT NULL AND pol.item.isFee = true")
    fun findAllByDeletedIsFalseAndItemIsFeeTrue(): List<PurchaseOrderLine>
}