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

import com.ffii.core.support.AbstractRepository
import com.ffii.fpsms.modules.logistic.entity.Logistic
import org.springframework.data.jpa.repository.Modifying
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import org.springframework.stereotype.Repository
import java.time.LocalTime
import java.util.Optional
import com.ffii.fpsms.modules.master.entity.projections.ShopAndTruck

@Repository
interface TruckRepository : AbstractRepository<Truck, Long> {

    fun findByShopIdAndDeletedFalse(shopId: Long): List<Truck>

    @Query("SELECT t FROM Truck t WHERE t.shop.id = :shopId AND t.deleted = false ORDER BY t.id ASC")
    fun findFirstByShopIdAndDeletedFalse(@Param("shopId") shopId: Long): List<Truck>

    //  使用新的 TruckLanceCode 字段名
    @Query("SELECT t FROM Truck t WHERE t.truckLanceCode = :truckLanceCode AND t.deleted = false")
    fun findByTruckLanceCodeAndDeletedFalse(@Param("truckLanceCode") truckLanceCode: String): Truck?


    //  按 ShopCode 查询
    @Query("SELECT t FROM Truck t WHERE t.shopCode = :shopCode AND t.deleted = false")
    fun findByShopCodeAndDeletedFalse(@Param("shopCode") shopCode: String): List<Truck>

    //  按 Store_id 查询
    fun findByStoreIdAndDeletedFalse(storeId: String): List<Truck>

    //  按 TruckLanceCode 查询
    fun findByTruckLanceCode(truckLanceCode: String): Truck?
    @Query("SELECT t FROM Truck t WHERE t.truckLanceCode = :truckLanceCode AND t.deleted = false")
    fun findAllByTruckLanceCodeAndDeletedFalse(@Param("truckLanceCode") truckLanceCode: String): List<Truck>

    /**
     * Same lane group as `findAllUniqueTruckLanceCodeAndRemarkCombinations`:
     * remark NULL / blank belong to one bucket; non-blank matches exactly.
     */
    @Query(
        """
        SELECT DISTINCT t FROM Truck t
        LEFT JOIN FETCH t.logistic
        LEFT JOIN FETCH t.shop
        WHERE t.truckLanceCode = :truckLanceCode
          AND t.deleted = false
          AND (
            (:blankRemark = true AND (t.remark IS NULL OR trim(t.remark) = ''))
            OR (:blankRemark = false AND trim(t.remark) = :exactRemark)
          )
        """
    )
    fun findAllByTruckLanceCodeAndRemarkAndDeletedFalse(
        @Param("truckLanceCode") truckLanceCode: String,
        @Param("blankRemark") blankRemark: Boolean,
        @Param("exactRemark") exactRemark: String?,
    ): List<Truck>

    /**
     * RouteBoard O(1) load: return all truck rows used by lanes, with logistic pre-fetched.
     * Frontend groups by (truckLanceCode, normalizedRemark) where normalizedRemark is:
     * - NULL / blank => ""
     * - else TRIM(remark)
     */
    @Query(
        """
        SELECT t FROM Truck t
        LEFT JOIN FETCH t.logistic
        LEFT JOIN FETCH t.shop
        WHERE t.deleted = false
          AND t.truckLanceCode IS NOT NULL
          AND trim(t.truckLanceCode) <> ''
        ORDER BY t.truckLanceCode ASC,
          CASE WHEN t.remark IS NULL OR trim(t.remark) = '' THEN '' ELSE trim(t.remark) END ASC,
          t.loadingSequence ASC,
          t.id ASC
        """
    )
    fun findAllForRouteBoard(): List<Truck>

    /**
     * 單一 UPDATE 寫入整條 lane 的 logistic，避免先 JOIN FETCH 載入再逐列 save（大車線會極慢）。
     */
    @Modifying(clearAutomatically = true, flushAutomatically = true)
    @Query(
        """
        UPDATE Truck t SET t.logistic = :logistic
        WHERE t.truckLanceCode = :truckLanceCode
          AND t.deleted = false
          AND (
            (:blankRemark = true AND (t.remark IS NULL OR trim(t.remark) = ''))
            OR (:blankRemark = false AND trim(t.remark) = :exactRemark)
          )
        """,
    )
    fun bulkUpdateLogisticForLaneGroup(
        @Param("logistic") logistic: Logistic?,
        @Param("truckLanceCode") truckLanceCode: String,
        @Param("blankRemark") blankRemark: Boolean,
        @Param("exactRemark") exactRemark: String?,
    ): Int

    fun findAllByTruckLanceCodeAndStoreIdAndDeletedFalse(truckLanceCode: String, storeId: String): List<Truck>
    fun findByShopNameAndStoreIdAndTruckLanceCode(shopName: String, storeId: String, truckLanceCode: String): Truck?
    /** 同店同樓層重複列時取 id 最小一筆，避免 NonUniqueResultException */
    fun findFirstByShopCodeAndStoreIdAndDeletedFalseOrderByIdAsc(
        shopCode: String,
        storeId: String,
    ): Truck?


    fun findByShopIdAndStoreId(shopId: Long, storeId: String): Truck?
    fun findAllByShopId(shopId :Long):List<Truck>
    //fun findByTruckLanceCode(truckLanceCode: String):List<Truck>
    //fun deleteByTruckLanceCodeAndDepartureTimeAndLoadingSequenceAndDistrictReferenceAndStoreId(truckLanceCode: String, departureTime: LocalTime, loadingSequence: Long, districtReference: Long, storeId: Long): String
    @Query("""
    SELECT t FROM Truck t 
    WHERE t.shop.id = :shopId 
      AND t.storeId = :storeId 
      AND t.deleted = false 
      AND t.truckLanceCode LIKE CONCAT('%', :dayOfWeekAbbr, '%')
    ORDER BY t.departureTime ASC
""")
fun findByShopIdAndStoreIdAndDayOfWeek(
    @Param("shopId") shopId: Long,
    @Param("storeId") storeId: String,
    @Param("dayOfWeekAbbr") dayOfWeekAbbr: String
): List<Truck>

    @Query(
        nativeQuery = true,
        value = """
        SELECT t.*
        FROM truck t
        INNER JOIN (
            SELECT TruckLanceCode,
                   COALESCE(NULLIF(TRIM(remark), ''), '') AS remark_norm,
                   MIN(id) AS min_id
            FROM truck
            WHERE deleted = false
              AND TruckLanceCode IS NOT NULL
            GROUP BY TruckLanceCode, COALESCE(NULLIF(TRIM(remark), ''), '')
        ) AS unique_combos
        ON t.id = unique_combos.min_id
        WHERE t.deleted = false
        ORDER BY t.TruckLanceCode, COALESCE(NULLIF(TRIM(t.remark), ''), '')
    """
    )
    fun findAllUniqueTruckLanceCodeAndRemarkCombinations(): List<Truck>

    @Query(
        nativeQuery = true,
        value = """
        SELECT s.id as id, t.ShopCode as code, t.ShopName as name, s.contactNo as contactNo, 
               s.contactEmail as contactEmail, s.contactName as contactName, 
               s.addr1 as addr1, s.addr2 as addr2, s.addr3 as addr3, s.type as type, 
               t.TruckLanceCode as truckLanceCode, t.DepartureTime as departureTime, 
               t.LoadingSequence as LoadingSequence, t.districtReference as districtReference, 
               t.Store_id as Store_id, t.remark as remark, t.id as truckId
        FROM shop s INNER JOIN truck t ON s.id = t.shopId
        WHERE t.TruckLanceCode = :truckLanceCode
          AND t.deleted = false
          AND s.deleted = false;
    """
    )
    fun findAllFromShopAndTruckByTruckLanceCodeAndDeletedFalse(@Param("truckLanceCode") truckLanceCode: String): List<ShopAndTruck>

    @Query(
        nativeQuery = true,
        value = """
        SELECT DISTINCT t.ShopName as name, t.ShopCode as code
        FROM truck t
        WHERE t.deleted = false
          AND t.ShopName IS NOT NULL
          AND t.ShopCode IS NOT NULL
          AND t.ShopName != ''
          AND t.ShopCode != ''
        ORDER BY t.ShopName, t.ShopCode
    """
    )
    fun findAllUniqueShopNamesAndCodesFromTrucks(): List<Map<String, String>>

    @Query(
        nativeQuery = true,
        value = """
        SELECT DISTINCT t.remark as remark
        FROM truck t
        WHERE t.deleted = false
          AND t.remark IS NOT NULL
          AND t.remark != ''
        ORDER BY t.remark
    """
    )
    fun findAllUniqueRemarksFromTrucks(): List<String>

    @Query(
        nativeQuery = true,
        value = """
        SELECT DISTINCT t.ShopCode as code
        FROM truck t
        WHERE t.deleted = false
          AND t.ShopCode IS NOT NULL
          AND t.ShopCode != ''
        ORDER BY t.ShopCode
    """
    )
    fun findAllUniqueShopCodesFromTrucks(): List<String>

    @Query(
        nativeQuery = true,
        value = """
        SELECT DISTINCT t.ShopName as name
        FROM truck t
        WHERE t.deleted = false
          AND t.ShopName IS NOT NULL
          AND t.ShopName != ''
        ORDER BY t.ShopName
    """
    )
    fun findAllUniqueShopNamesFromTrucks(): List<String>


    @Query("SELECT t FROM Truck t WHERE t.truckLanceCode LIKE CONCAT('%', :truckLanceCode, '%') AND t.deleted = false")
fun findAllByTruckLanceCodeContainingAndDeletedFalse(@Param("truckLanceCode") truckLanceCode: String): List<Truck>
}