package com.ffii.fpsms.modules.stock.entity

import com.ffii.core.support.AbstractRepository
import com.ffii.fpsms.modules.master.entity.Items
import com.ffii.fpsms.modules.stock.entity.projection.InventoryInfo
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.Query
import org.springframework.stereotype.Repository
import java.io.Serializable
import java.util.Optional

@Repository
interface InventoryRepository: AbstractRepository<Inventory, Long> {
    fun findInventoryInfoByDeletedIsFalse(): List<InventoryInfo>

    @Query(
    """
    SELECT i FROM Inventory i
    WHERE (:code IS NULL OR i.item.code LIKE CONCAT('%', :code, '%'))
      AND (:name IS NULL OR i.item.name LIKE CONCAT('%', :name, '%'))
      AND (:type IS NULL OR :type = '' OR i.item.type = :type)
      AND i.deleted = false
      AND EXISTS (
        SELECT 1 FROM ItemUom iu
        WHERE iu.item.id = i.item.id
          AND iu.deleted = false
          AND iu.baseUnit = true
          AND iu.uom.id = i.uom.id
      )
    """
)
    fun findInventoryInfoByItemCodeContainsAndItemNameContainsAndItemTypeAndDeletedIsFalse(code: String, name: String, type: String, pageable: Pageable): Page<InventoryInfo>

    @Query("SELECT i FROM Inventory i " +
            "WHERE (:code IS NULL OR i.item.code LIKE CONCAT('%', :code, '%')) " +
            "AND (:name IS NULL OR i.item.name LIKE CONCAT('%', :name, '%')) " +
            "AND (:type IS NULL OR :type = '' OR i.item.type = :type) " +
            "AND i.item.id IN :itemIds " +
            "AND i.deleted = false")
    fun findInventoryInfoByItemCodeContainsAndItemNameContainsAndItemTypeAndItemIdInAndDeletedIsFalse(
        code: String,
        name: String,
        type: String,
        itemIds: List<Long>,
        pageable: Pageable
    ): Page<InventoryInfo>

    /**
     * FP-MTMS Version Checklist | Functions Ref. No. 19 | v1.0.0 | 2026-07-17
     * Inventory search page only: no baseUnit/uomId match required;
     * one row per item = latest inventory id (no larger id for same item).
     */
    @Query(
        """
        SELECT i FROM Inventory i
        WHERE (:code IS NULL OR :code = '' OR LOWER(i.item.code) LIKE LOWER(CONCAT('%', :code, '%')))
          AND (:name IS NULL OR :name = '' OR LOWER(i.item.name) LIKE LOWER(CONCAT('%', :name, '%')))
          AND (:type IS NULL OR :type = '' OR i.item.type = :type)
          AND i.deleted = false
          AND NOT EXISTS (
            SELECT 1 FROM Inventory i2
            WHERE i2.item.id = i.item.id
              AND i2.deleted = false
              AND i2.id > i.id
          )
        """
    )
    fun findLatestInventoryInfoByItemCodeContainsAndItemNameContainsAndItemTypeAndDeletedIsFalse(
        code: String,
        name: String,
        type: String,
        pageable: Pageable,
    ): Page<InventoryInfo>

    /** FP-MTMS Version Checklist | Functions Ref. No. 19 | v1.0.0 | 2026-07-17 */
    @Query(
        """
        SELECT i FROM Inventory i
        WHERE (:code IS NULL OR :code = '' OR LOWER(i.item.code) LIKE LOWER(CONCAT('%', :code, '%')))
          AND (:name IS NULL OR :name = '' OR LOWER(i.item.name) LIKE LOWER(CONCAT('%', :name, '%')))
          AND (:type IS NULL OR :type = '' OR i.item.type = :type)
          AND i.item.id IN :itemIds
          AND i.deleted = false
          AND NOT EXISTS (
            SELECT 1 FROM Inventory i2
            WHERE i2.item.id = i.item.id
              AND i2.deleted = false
              AND i2.id > i.id
          )
        """
    )
    fun findLatestInventoryInfoByItemCodeContainsAndItemNameContainsAndItemTypeAndItemIdInAndDeletedIsFalse(
        code: String,
        name: String,
        type: String,
        itemIds: List<Long>,
        pageable: Pageable,
    ): Page<InventoryInfo>

    fun findInventoryInfoByItemIdInAndDeletedIsFalse(itemIds: List<Serializable>): List<InventoryInfo>

    fun findInventoryInfoByItemInAndDeletedIsFalse(items: List<Items>): List<InventoryInfo>

    fun findByItemId(itemId: Long): Optional<Inventory>
    fun findAllByItemIdInAndDeletedIsFalse(itemIds: Collection<Long>): List<Inventory>

    @Query("SELECT i FROM Inventory i WHERE i.item.id = :itemId AND i.deleted = false")
    fun findAllByItemIdAndDeletedIsFalse(itemId: Long): List<Inventory>

    fun findFirstByItemIdAndDeletedIsFalseOrderByIdAsc(itemId: Long): Inventory?

    /** 與 item_uom 中 baseUnit=true 之 uomId 對齊時使用，避免同一 item 多筆 inventory 時 NonUniqueResult */
    fun findFirstByItemIdAndUomIdAndDeletedIsFalseOrderByIdAsc(itemId: Long, uomId: Long): Inventory?
}