package com.ffii.fpsms.modules.deliveryOrder.service

import com.ffii.fpsms.m18.entity.M18DataLogRepository
import com.ffii.fpsms.m18.service.M18DataLogService
import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrder
import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfo
import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus
import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderRequest
import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderStatusRequest
import com.ffii.fpsms.modules.master.service.CurrencyService
import com.ffii.fpsms.modules.master.service.ShopService
import com.ffii.fpsms.modules.user.entity.UserRepository
import com.ffii.fpsms.modules.user.service.UserService
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.io.IOException
import kotlin.jvm.optionals.getOrDefault
import kotlin.jvm.optionals.getOrNull
import com.ffii.fpsms.modules.deliveryOrder.web.models.DoDetailResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.DoDetailLineResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.ReleaseDoRequest
import com.ffii.fpsms.modules.pickOrder.web.models.SavePickOrderRequest
import com.ffii.fpsms.modules.pickOrder.web.models.SavePickOrderLineRequest
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderType
import com.ffii.fpsms.modules.pickOrder.service.PickOrderService
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrder
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRepository
import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus
import java.math.BigDecimal
import com.ffii.fpsms.modules.master.web.models.MessageResponse
import java.time.LocalDateTime
import com.ffii.fpsms.modules.deliveryOrder.web.models.AssignByStoreRequest
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecord
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecordRepository
import com.ffii.fpsms.modules.deliveryOrder.web.models.*  //  导入
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus
import com.ffii.fpsms.modules.pickOrder.entity.TruckRepository
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import com.ffii.core.support.JdbcDao
import com.ffii.fpsms.modules.pickOrder.entity.Truck
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRepository
import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrderRepository
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRecordRepository
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRecord
import org.springframework.context.annotation.Lazy
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository
import com.ffii.fpsms.modules.deliveryOrder.web.models.TicketReleaseTableResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.TruckScheduleDashboardResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.SearchDeliveryOrderInfoRequest
import com.ffii.core.response.RecordsRes
import org.springframework.data.domain.PageRequest
import java.time.temporal.ChronoUnit
@Service
open class DoPickOrderService(
    private val doPickOrderRepository: DoPickOrderRepository,
    private val doPickOrderRecordRepository: DoPickOrderRecordRepository,
    private val userRepository: UserRepository,
    private val pickOrderRepository: PickOrderRepository,
    private val jdbcDao: JdbcDao,  //  添加这行
    private val truckRepository: TruckRepository, 
    private val doPickOrderLineRepository: DoPickOrderLineRepository,
    @Lazy private val deliveryOrderRepository: DeliveryOrderRepository,
    private val doPickOrderLineRecordRepository: DoPickOrderLineRecordRepository,
    private val pickOrderLineRepository: PickOrderLineRepository
) {
    open fun findReleasedDoPickOrders(): List<DoPickOrder> {
        return doPickOrderRepository.findByTicketStatusIn(
            listOf(DoPickOrderStatus.released, DoPickOrderStatus.pending)
        )
    }
    open fun allDeliveryOrdersByPage(request: SearchDeliveryOrderInfoRequest): RecordsRes<DeliveryOrderInfo> {
        val pageable = PageRequest.of(request.pageNum ?: 0, request.pageSize ?: 10);
        println("allDeliveryOrdersByPage")
        println(request)
        val response = deliveryOrderRepository.findDeliveryOrderInfoByCodeContainsAndShopNameContainsAndDeletedIsFalseOrderByIdDesc(
            code = request.code ?: "",
            shopName = request.shopName ?: "",
            pageable = pageable
        )
        val estimatedArrivalDate = request.estimatedArrivalDate
        val status = request.status
        val records = response.content
            .filter {
                // 如果提供了 estimatedArrivalDate，只匹配同一天的记录
                (estimatedArrivalDate == null || (it.estimatedArrivalDate != null &&
                        it.estimatedArrivalDate!!.toLocalDate() == estimatedArrivalDate.toLocalDate())) &&
                        (status == null || it.status == status)
            }
        val total = response.totalElements
        return RecordsRes<DeliveryOrderInfo>(records, total.toInt());
    }
    open fun getNextTicketNumber(datePrefix: String, storeId: String): String {
        println("  DEBUG: Getting next ticket number for date prefix: $datePrefix, store: $storeId")
        try {
            val sanitizedStoreId = storeId.replace("/", "")
            val shortDatePrefix = if (datePrefix.length == 8) {
                datePrefix.substring(2)  // 从 20251016 变成 251016
            } else {
                datePrefix
            }
            //  修改搜索模式为新格式
            val searchPattern = "TI-${shortDatePrefix}-${sanitizedStoreId}-"  // T-20250915-4F-
            val todayTickets = doPickOrderRepository.findByTicketNoStartingWith(searchPattern)
            println("  DEBUG: Found ${todayTickets.size} existing tickets with prefix $searchPattern")
            todayTickets.forEach { ticket ->
                println("  DEBUG: Existing ticket: ${ticket.ticketNo}, Status: ${ticket.ticketStatus}")
            }
            val nextNumber = (todayTickets.size + 1).toString().padStart(3, '0')
            //  修改生成格式
            val ticketNumber = "TI-${datePrefix}-${sanitizedStoreId}-${nextNumber}"  // T-20250915-4F-001
            println("  DEBUG: Generated ticket number: $ticketNumber")
            return ticketNumber
        } catch (e: Exception) {
            println("❌ ERROR in getNextTicketNumber: ${e.message}")
            e.printStackTrace()
            throw e
        }
    }

    open fun save(record: DoPickOrder): DoPickOrder {
        return doPickOrderRepository.save(record)
    }

    open fun findByStoreIdOrderByTruckDepartureTime(storeId: String): List<DoPickOrder> {
        return doPickOrderRepository.findByStoreIdAndTicketStatusOrderByTruckDepartureTimeAsc(
            storeId, DoPickOrderStatus.pending
        )
    }

    // Add these missing methods
    open fun assignByStore(request: AssignByStoreRequest): MessageResponse {
        // TODO: Implement store-based assignment logic
        return MessageResponse(
            id = null,
            code = null,
            name = null,
            type = null,
            message = "Store-based assignment not implemented yet",
            errorPosition = null,
            entity = null
        )
    }

    open fun releaseAssignedByStore(request: AssignByStoreRequest): MessageResponse {
        // TODO: Implement store-based release logic
        return MessageResponse(
            id = null,
            code = null,
            name = null,
            type = null,
            message = "Store-based release not implemented yet",
            errorPosition = null,
            entity = null
        )
    }

    //  Updated method to set ticketReleaseTime when assigning order to user
    open fun updateHandledByForPickOrder(pickOrderId: Long, userId: Long): List<DoPickOrder> {
        val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId)
        val user = userRepository.findById(userId).orElse(null)  //  改用 orElse(null)
        val handlerName = user?.name ?: "Unknown"
        doPickOrders.forEach {
            it.handledBy = userId
            it.handlerName = handlerName
            it.ticketStatus = DoPickOrderStatus.released
            it.ticketReleaseTime = LocalDateTime.now()
        }
        return doPickOrderRepository.saveAll(doPickOrders)
    }

    open fun completeDoPickOrdersForPickOrder(pickOrderId: Long): List<DoPickOrder> {
        val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId)
        doPickOrders.forEach {
            it.ticketStatus = DoPickOrderStatus.completed
            it.ticketCompleteDateTime = LocalDateTime.now()
        }
        val savedDoPickOrders = doPickOrderRepository.saveAll(doPickOrders)
        
        //  同步更新相关的delivery_order状态
        savedDoPickOrders.forEach { doPickOrder ->
            if (doPickOrder.doOrderId != null) {
                val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(doPickOrder.doOrderId!!)
                if (deliveryOrder != null && deliveryOrder.status != DeliveryOrderStatus.COMPLETED) {
                    deliveryOrder.status = DeliveryOrderStatus.COMPLETED
                    deliveryOrderRepository.save(deliveryOrder)
                    println(" Updated delivery order ${doPickOrder.doOrderId} status to completed")
                }
            }
        }
        
        return savedDoPickOrders
    }

    //  New method to remove do_pick_order records when auto-assigning by store
    //  修改方法：先复制记录到record表，再删除原记录
    @Transactional
    open fun removeDoPickOrdersForPickOrder(pickOrderId: Long): Int {
        val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId)
        var deletedCount = 0
        
        doPickOrders.forEach { doPickOrder ->
            //  第一步：复制 do_pick_order 到 do_pick_order_record
            val doPickOrderRecord = DoPickOrderRecord(
                recordId = doPickOrder.id,
                storeId = doPickOrder.storeId?: "",
                ticketNo = doPickOrder.ticketNo?: "",
                ticketStatus = DoPickOrderStatus.completed, // 设置为completed状态
                truckId = doPickOrder.truckId,
                pickOrderId = doPickOrder.pickOrderId,
                truckDepartureTime = doPickOrder.truckDepartureTime,
                shopId = doPickOrder.shopId,
                handledBy = doPickOrder.handledBy,
                handlerName = doPickOrder.handlerName,
                doOrderId = doPickOrder.doOrderId,
                pickOrderCode = doPickOrder.pickOrderCode,
                deliveryOrderCode = doPickOrder.deliveryOrderCode,
                loadingSequence = doPickOrder.loadingSequence,
                ticketReleaseTime = doPickOrder.ticketReleaseTime,
                ticketCompleteDateTime = LocalDateTime.now(), // 设置完成时间
                truckLanceCode = doPickOrder.truckLanceCode,
                shopCode = doPickOrder.shopCode,
                shopName = doPickOrder.shopName,
                requiredDeliveryDate = doPickOrder.requiredDeliveryDate
            )
            val savedRecord = doPickOrderRecordRepository.save(doPickOrderRecord)
            println(" Copied do_pick_order ${doPickOrder.id} to do_pick_order_record")
            
            //  第二步：复制 do_pick_order_line 到 do_pick_order_line_record
            //  第二步：复制 do_pick_order_line 到 do_pick_order_line_record
            val doPickOrderLines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(doPickOrder.id!!)
            doPickOrderLines.forEach { line ->
                val doPickOrderLineRecord = DoPickOrderLineRecord()
                doPickOrderLineRecord.recordId = line.id //  使用默认构造函数
                doPickOrderLineRecord.doPickOrderId = savedRecord.id //  设置属性
                doPickOrderLineRecord.pickOrderId = line.pickOrderId
                doPickOrderLineRecord.doOrderId = line.doOrderId
                doPickOrderLineRecord.pickOrderCode = line.pickOrderCode
                doPickOrderLineRecord.deliveryOrderCode = line.deliveryOrderCode
                doPickOrderLineRecord.status = line.status
                doPickOrderLineRecordRepository.save(doPickOrderLineRecord)
                println(" Copied do_pick_order_line ${line.id} to do_pick_order_line_record")
            }
            
            //  第三步：删除原始的 do_pick_order_line 记录
            if (doPickOrderLines.isNotEmpty()) {
                doPickOrderLineRepository.deleteAll(doPickOrderLines)
                println(" Deleted ${doPickOrderLines.size} do_pick_order_line records")
            }
            
            //  第四步：删除原始的 do_pick_order 记录
            doPickOrderRepository.delete(doPickOrder)
            deletedCount++
            println(" Deleted do_pick_order ${doPickOrder.id}")
        }
        
        return deletedCount
    }

    open fun saveRecord(record: DoPickOrderRecord): DoPickOrderRecord {
        return doPickOrderRecordRepository.save(record)
    }

    //  Add method to update DoPickOrderRecord status
    open fun updateRecordHandledByForPickOrder(pickOrderId: Long, userId: Long): List<DoPickOrderRecord> {
        val doPickOrderRecords = doPickOrderRecordRepository.findByPickOrderId(pickOrderId)
        val user = userRepository.findById(userId).orElse(null)  //  改用 orElse(null)
        val handlerName = user?.name ?: "Unknown"
        doPickOrderRecords.forEach {
            it.handledBy = userId
            it.handlerName = handlerName
            it.ticketStatus = DoPickOrderStatus.released
            it.ticketReleaseTime = LocalDateTime.now()
        }
        return doPickOrderRecordRepository.saveAll(doPickOrderRecords)
    }

    //  Add method to complete DoPickOrderRecord
    open fun completeDoPickOrderRecordsForPickOrder(pickOrderId: Long): List<DoPickOrderRecord> {
        val doPickOrderRecords = doPickOrderRecordRepository.findByPickOrderId(pickOrderId)
        doPickOrderRecords.forEach {
            it.ticketStatus = DoPickOrderStatus.completed
            it.ticketCompleteDateTime = LocalDateTime.now()  //  设置完成时间
        }
        return doPickOrderRecordRepository.saveAll(doPickOrderRecords)
    }

    // Add method to find do_pick_order records by pick order ID
    open fun findByPickOrderId(pickOrderId: Long): List<DoPickOrder> {
        return doPickOrderRepository.findByPickOrderId(pickOrderId)
    }

    /**
     * 撤銷使用者對 do_pick_order 的領取：清空 handled_by，狀態回到 pending，並解除關聯 pick_order 的 assignTo。
     * 僅適用於尚未完成的單據。
     */
    @Transactional
    open fun revertUserAssignment(doPickOrderId: Long): MessageResponse {
        val dpo = doPickOrderRepository.findById(doPickOrderId).orElse(null)
            ?: return MessageResponse(
                id = null,
                code = "NOT_FOUND",
                name = null,
                type = null,
                message = "do_pick_order not found",
                errorPosition = null,
                entity = null,
            )
        if (dpo.ticketStatus == DoPickOrderStatus.completed) {
            return MessageResponse(
                id = dpo.id,
                code = "INVALID_STATUS",
                name = dpo.ticketNo,
                type = null,
                message = "Cannot revert a completed ticket",
                errorPosition = null,
                entity = null,
            )
        }
        if (dpo.handledBy == null) {
            return MessageResponse(
                id = dpo.id,
                code = "NOT_ASSIGNED",
                name = dpo.ticketNo,
                type = null,
                message = "No user assignment to revert",
                errorPosition = null,
                entity = null,
            )
        }

        dpo.handledBy = null
        dpo.handlerName = null
        dpo.ticketStatus = DoPickOrderStatus.pending
        dpo.ticketReleaseTime = null
        doPickOrderRepository.save(dpo)

        val lines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(doPickOrderId)
        lines.forEach { line ->
            val pid = line.pickOrderId ?: return@forEach
            pickOrderRepository.findById(pid).ifPresent { po ->
                po.assignTo = null
                po.status = PickOrderStatus.PENDING
                pickOrderRepository.save(po)
            }
            val records = doPickOrderRecordRepository.findByPickOrderId(pid)
            records.forEach { r ->
                if (r.ticketStatus != DoPickOrderStatus.completed) {
                    r.handledBy = null
                    r.handlerName = null
                    r.ticketStatus = DoPickOrderStatus.pending
                    r.ticketReleaseTime = null
                }
            }
            if (records.isNotEmpty()) {
                doPickOrderRecordRepository.saveAll(records)
            }
        }

        return MessageResponse(
            id = dpo.id,
            code = "SUCCESS",
            name = dpo.ticketNo,
            type = null,
            message = "Assignment reverted",
            errorPosition = null,
            entity = null,
        )
    }

    open fun updateDoOrderIdForPickOrder(pickOrderId: Long, doOrderId: Long): List<DoPickOrder> {
        val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId)
        doPickOrders.forEach {
            it.doOrderId = doOrderId
        }
        return doPickOrderRepository.saveAll(doPickOrders)
    }
    fun getSummaryByStore(storeId: String, requiredDate: LocalDate?, releaseType: String): StoreLaneSummary {
        val targetDate = requiredDate ?: LocalDate.now()
        //println("  DEBUG: Getting summary for store=$storeId, date=$targetDate")
        
        val actualStoreId = when (storeId) {
            "2/F" -> "2/F"
            "4/F" -> "4/F"
            else -> storeId
        }

        /*
        val allRecords = doPickOrderRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn(
            actualStoreId,
            targetDate,
            listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed)
        )
        */
        val allRecords = doPickOrderRepository
    .findByStoreIdAndRequiredDeliveryDateAndTicketStatusInWithNonIssueLines(
        actualStoreId, targetDate, 
        listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed)
    )
        val filteredByReleaseType = when (releaseType.lowercase()) {
            "batch" -> allRecords.filter { it.releaseType == "batch" }
            "single" -> allRecords.filter { it.releaseType == "single" }
            else -> allRecords  // "all" 或其他值，不过滤
        }
        // 添加 finishedRecords 查询
        val finishedRecords = doPickOrderRecordRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn(
            actualStoreId,
            targetDate,
            listOf(DoPickOrderStatus.completed)
        )
        val filteredFinishedRecords = when (releaseType.lowercase()) {
            "batch" -> finishedRecords.filter { it.releaseType == "batch" }
            "single" -> finishedRecords.filter { it.releaseType == "single" }
            else -> finishedRecords  // "all" 或其他值，不过滤
        }
        //println("  DEBUG: Found ${allRecords.size} records for date $targetDate")
       // println("  DEBUG: Found ${finishedRecords.size} finished records for date $targetDate")
        /*
        val filteredRecords = filteredByReleaseType.filter { doPickOrder ->
            val hasNonIssueLines = checkDoPickOrderHasNonIssueLines(doPickOrder.id!!)
            if (!hasNonIssueLines) {
                println("  DEBUG: Filtering out DoPickOrder ${doPickOrder.id} - all lines are issues")
            }
            hasNonIssueLines
        }
        */
       // println("  DEBUG: After filtering, ${filteredRecords.size} records remain")
        
        val grouped = filteredByReleaseType.groupBy { it.truckDepartureTime to it.truckLanceCode }
            .mapValues { (key, list) ->
                val (truckDepartureTime, truckLanceCode) = key
                // 计算匹配的 finishedRecords 数量
               // val matchingFinishedCount = finishedRecords.count { record ->
                    //(record.truckDepartureTime == truckDepartureTime) && 
                   // (record.truckLanceCode == truckLanceCode)
             //   }
             val matchingFinishedCount = filteredFinishedRecords.count { record ->
                record.truckDepartureTime == truckDepartureTime &&
                record.truckLanceCode == truckLanceCode
            }
               // println("  DEBUG: Group key - truckDepartureTime: $truckDepartureTime, truckLanceCode: $truckLanceCode")
                //println("  DEBUG: Found ${list.size} active records in this group")
                //println("  DEBUG: Found $matchingFinishedCount finished records matching this group")
                LaneBtn(
                    truckLanceCode = list.first().truckLanceCode ?: "",
                    unassigned = list.count { it.handledBy == null },
                    total = list.size + matchingFinishedCount  // 添加 finishedRecords 计数
                )
            }
        
        val timeGroups = grouped.entries
            .groupBy { it.key.first }
            .mapValues { (_, entries) ->
                entries.map { it.value }
                    .filter { it.unassigned > 0 }
                    .sortedBy { it.truckLanceCode }
            }
            .filterValues { lanes -> lanes.any { it.unassigned > 0 } }
            .toSortedMap(compareBy { it })
            .entries.take(4)
            .map { (time, lanes) ->
                LaneRow(
                    truckDepartureTime = time?.toString() ?: "",
                    lanes = lanes
                )
            }
            val defaultTruckCount = allRecords.count { 
                it.truckLanceCode == "車線-X" && it.requiredDeliveryDate == targetDate
            }
        return StoreLaneSummary(storeId = storeId, rows = timeGroups, defaultTruckCount = defaultTruckCount)
    }
    private fun checkDoPickOrderHasNonIssueLines(doPickOrderId: Long): Boolean {
        try {
            // 1. 获取该 do_pick_order 的所有 do_pick_order_line 数量
            val totalLinesSql = """
                SELECT COUNT(*) as total_lines
                FROM fpsmsdb.do_pick_order_line dpol
                WHERE dpol.do_pick_order_id = :doPickOrderId 
                AND dpol.deleted = 0
            """.trimIndent()
            
            val totalLinesResult = jdbcDao.queryForList(totalLinesSql, mapOf("doPickOrderId" to doPickOrderId))
            val totalLines = (totalLinesResult.firstOrNull()?.get("total_lines") as? Number)?.toInt() ?: 0
            
            if (totalLines == 0) {
                return true  // 没有 lines，不算过滤
            }
            
            // 2. 获取非 "issue" 状态的 lines 数量
            val nonIssueLinesSql = """
                SELECT COUNT(*) as non_issue_lines
                FROM fpsmsdb.do_pick_order_line dpol
                WHERE dpol.do_pick_order_id = :doPickOrderId 
                AND dpol.deleted = 0
                AND (dpol.status IS NULL OR dpol.status != 'issue')
            """.trimIndent()
            
            val nonIssueLinesResult = jdbcDao.queryForList(nonIssueLinesSql, mapOf("doPickOrderId" to doPickOrderId))
            val nonIssueLines = (nonIssueLinesResult.firstOrNull()?.get("non_issue_lines") as? Number)?.toInt() ?: 0
            
            // 3. 只有当所有 lines 都是 "issue" 状态时才过滤掉
            val hasNonIssueLines = nonIssueLines > 0
            
           // println("  DEBUG: DoPickOrder $doPickOrderId - Total lines: $totalLines, Non-issue lines: $nonIssueLines, Has non-issue lines: $hasNonIssueLines")
            
            return hasNonIssueLines
            
        } catch (e: Exception) {
            println("❌ Error checking non-issue lines for do_pick_order $doPickOrderId: ${e.message}")
            return true  // 出错时不过滤
        }
    }
    //  修复：把 assignByLane 移到类里面
    open fun assignByLane(request: AssignByLaneRequest): MessageResponse {
        val user = userRepository.findById(request.userId).orElse(null)
            ?: return MessageResponse(
                id = null, code = "USER_NOT_FOUND", name = null, type = null,
                message = "User not found", errorPosition = null, entity = null
            )
    
        //  转换 storeId 格式：'2/F' -> '2F/F', '4/F' -> '4F/F'
        val actualStoreId = when (request.storeId) {
            "2/F" -> "2/F"  //  保持原格式
            "4/F" -> "4/F"  //  保持原格式
            else -> request.storeId
        }
        println("  DEBUG: assignByLane - Converting storeId from '${request.storeId}' to '$actualStoreId'")
    
        val candidates = doPickOrderRepository
            .findByStoreIdAndTicketStatusOrderByTruckDepartureTimeAsc(
                actualStoreId,
                DoPickOrderStatus.pending
            )
            .filter { it.truckLanceCode == request.truckLanceCode }
    
        if (candidates.isEmpty()) {
            return MessageResponse(
                id = null, code = "NO_ORDERS", name = null, type = null,
                message = "No available pick order(s) for this lane.", errorPosition = null, entity = null
            )
        }
    
        val firstOrder = candidates.first()
        
        //  更新 do_pick_order
        firstOrder.handledBy = request.userId
        firstOrder.handlerName = user.name
        firstOrder.ticketStatus = DoPickOrderStatus.released
        firstOrder.ticketReleaseTime = LocalDateTime.now()
        doPickOrderRepository.save(firstOrder)
    
        //  关键修改：获取这个 do_pick_order 下的所有 pick orders 并分配给用户
        val doPickOrderLines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(firstOrder.id!!)
        //println("  DEBUG: Found ${doPickOrderLines.size} pick orders in do_pick_order ${firstOrder.id}")
        
        doPickOrderLines.forEach { line ->
            if (line.pickOrderId != null) {
                val pickOrder = pickOrderRepository.findById(line.pickOrderId!!).orElse(null)
                if (pickOrder != null) {
                    pickOrder.assignTo = user
                    pickOrder.status = PickOrderStatus.RELEASED
                    pickOrderRepository.save(pickOrder)
                    println("  DEBUG: Assigned pick order ${line.pickOrderId} to user ${request.userId}")
                } else {
                    println("⚠️ WARNING: Pick order ${line.pickOrderId} not found")
                }
            }
        }
    
        //  同步更新 do_pick_order_record（如果有的话）
        doPickOrderLines.forEach { line ->
            if (line.pickOrderId != null) {
                val records = doPickOrderRecordRepository.findByPickOrderId(line.pickOrderId!!)
                records.forEach { record ->
                    record.handledBy = request.userId
                    record.handlerName = user.name
                    record.ticketStatus = DoPickOrderStatus.released
                    record.ticketReleaseTime = LocalDateTime.now()
                }
                if (records.isNotEmpty()) {
                    doPickOrderRecordRepository.saveAll(records)
                    println("  DEBUG: Updated ${records.size} do_pick_order_record for pick order ${line.pickOrderId}")
                }
            }
        }
    
        return MessageResponse(
            id = firstOrder.id,
            code = "SUCCESS",
            name = null,
            type = null,
            message = "Assigned ${doPickOrderLines.size} pick order(s) from lane ${request.truckLanceCode}",
            errorPosition = null,
            entity = mapOf(
                "doPickOrderId" to firstOrder.id,
                "ticketNo" to firstOrder.ticketNo,
                "numberOfPickOrders" to doPickOrderLines.size,
                "pickOrderIds" to doPickOrderLines.mapNotNull { it.pickOrderId }
            )
        )
    }

    // 在 DoPickOrderService 类中添加这个方法
    open fun determineStoreId(doOrderId: Long): String {
        val sql = """
        SELECT 
            dol.deliveryOrderId,
            w.store_id,
            SUM(ill.inQty - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) AS total_inventory
        FROM fpsmsdb.delivery_order_line dol
        LEFT JOIN fpsmsdb.inventory_lot il ON il.itemId = dol.itemId AND il.deleted = 0
        LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.inventoryLotId = il.id AND ill.deleted = 0
        LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId AND w.deleted = 0
        WHERE dol.deleted = 0 AND dol.deliveryOrderId = :doOrderId
        GROUP BY dol.deliveryOrderId, w.store_id
        ORDER BY total_inventory DESC
        LIMIT 1
    """.trimIndent()

        val results = jdbcDao.queryForList(sql, mapOf("doOrderId" to doOrderId))
        return if (results.isNotEmpty()) {
            val storeId = results.first()["store_id"] as? String ?: "2F"
            when (storeId) {
                "2F" -> "2/F"
                "4F" -> "4/F"
                "3F" -> "3/F"
                else -> "2/F"
            }
        } else {
            "2/F" // 默认值
        }
    }

    open fun selectTruck(shopId: Long?, storeId: String): Truck? {
        if (shopId == null) return null

        val storeId= when (storeId) {
            "2F" -> "2F"
            "4F" -> "4F"
            "3F" -> "3F"
            "3/F" -> "3F"
            else -> "2F"
        }
        val defaultTruckId = 5577L
        val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId)
        return trucks.find { it.storeId == storeId } ?: truckRepository.findById(defaultTruckId).orElse(null)
    }

    open fun finishDoPickOrder(doPickOrderId: Long): MessageResponse {
        val doPickOrder = doPickOrderRepository.findById(doPickOrderId).orElse(null)
            ?: return MessageResponse(
                id = null,
                code = "NOT_FOUND",
                name = null,
                type = null,
                message = "DO Pick Order not found",
                errorPosition = null,
                entity = null
            )

        try {
            // 确定 store_id 和 truck
            val storeId = determineStoreId(doPickOrder.doOrderId ?: 0L)
            val truck = selectTruck(doPickOrder.shopId, storeId)

            // 生成 ticket 编号
            val targetDate = doPickOrder.requiredDeliveryDate ?: LocalDate.now()
            val datePrefix = targetDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"))
            val ticketNumber = getNextTicketNumber(datePrefix, storeId)

            // 更新 do_pick_order
            doPickOrder.storeId = storeId
            doPickOrder.ticketNo = ticketNumber
            doPickOrder.truckId = truck?.id
            doPickOrder.truckDepartureTime = truck?.departureTime
            doPickOrder.truckLanceCode = truck?.truckLanceCode

            val updatedDoPickOrder = doPickOrderRepository.save(doPickOrder)

            // 创建 do_pick_order_record
            val doPickOrderRecord = DoPickOrderRecord(
                recordId =doPickOrder.id,
                storeId = storeId,
                ticketNo = ticketNumber,
                ticketStatus = DoPickOrderStatus.pending,
                truckId = truck?.id,
                pickOrderId = doPickOrder.pickOrderId,
                truckDepartureTime = truck?.departureTime,
                shopId = doPickOrder.shopId,
                handledBy = null,
                doOrderId = doPickOrder.doOrderId,
                pickOrderCode = doPickOrder.pickOrderCode,
                deliveryOrderCode = doPickOrder.deliveryOrderCode,
                loadingSequence = doPickOrder.loadingSequence,
                truckLanceCode = truck?.truckLanceCode,
                shopCode = doPickOrder.shopCode,
                shopName = doPickOrder.shopName,
                requiredDeliveryDate = targetDate
            )

            doPickOrderRecordRepository.save(doPickOrderRecord)

            return MessageResponse(
                id = updatedDoPickOrder.id,
                code = "SUCCESS",
                name = null,
                type = null,
                message = "DO Pick Order finished successfully",
                errorPosition = null,
                entity = mapOf("ticketNo" to ticketNumber)
            )
        } catch (e: Exception) {
            return MessageResponse(
                id = null,
                code = "ERROR",
                name = null,
                type = null,
                message = "Error finishing DO Pick Order: ${e.message}",
                errorPosition = null,
                entity = null
            )
        }
    }


    open fun getTicketReleaseTable(startDate: LocalDate? = null, endDate: LocalDate? = null): List<TicketReleaseTableResponse> {
        val doPickOrders = if (startDate != null && endDate != null) {
            doPickOrderRepository.findAllByDeletedFalseAndRequiredDeliveryDateBetween(startDate, endDate)
        } else {
            doPickOrderRepository.findAllByDeletedFalseOrderByTicketReleaseTimeDesc()
        }

        val doPickOrderRecords = if (startDate != null && endDate != null) {
            doPickOrderRecordRepository.findAllByDeletedFalseAndRequiredDeliveryDateBetween(startDate, endDate)
        } else {
            doPickOrderRecordRepository.findAllByDeletedFalseOrderByTicketReleaseTimeDesc()
        }

        val doPickOrderResponses = doPickOrders.map { doPickOrder ->
            TicketReleaseTableResponse(
                id = doPickOrder.id,
                storeId = doPickOrder.storeId,
                ticketNo = doPickOrder.ticketNo,
                pickOrderId = doPickOrder.pickOrderId,
                doOrderId = doPickOrder.doOrderId,
                pickOrderCode = doPickOrder.pickOrderCode,
                deliveryOrderCode = doPickOrder.deliveryOrderCode,
                loadingSequence = doPickOrder.loadingSequence,
                ticketStatus = doPickOrder.ticketStatus?.name,
                truckId = doPickOrder.truckId,
                truckDepartureTime = doPickOrder.truckDepartureTime,
                shopId = doPickOrder.shopId,
                handledBy = doPickOrder.handledBy,
                ticketReleaseTime = doPickOrder.ticketReleaseTime,
                ticketCompleteDateTime = doPickOrder.ticketCompleteDateTime,
                truckLanceCode = doPickOrder.truckLanceCode,
                shopCode = doPickOrder.shopCode,
                shopName = doPickOrder.shopName,
                requiredDeliveryDate = doPickOrder.requiredDeliveryDate,
                handlerName = doPickOrder.handlerName,
                numberOfFGItems = countFGItems(doPickOrder),
                isActiveDoPickOrder = true,
            )
        }

        val doPickOrderRecordResponses = doPickOrderRecords.map { record ->
                    TicketReleaseTableResponse(
                id = record.id,
                storeId = record.storeId,
                ticketNo = record.ticketNo,
                pickOrderId = record.pickOrderId,
                doOrderId = record.doOrderId,
                pickOrderCode = record.pickOrderCode,
                deliveryOrderCode = record.deliveryOrderCode,
                loadingSequence = record.loadingSequence,
                ticketStatus = record.ticketStatus?.name,
                truckId = record.truckId,
                truckDepartureTime = record.truckDepartureTime,
                shopId = record.shopId,
                handledBy = record.handledBy,
                ticketReleaseTime = record.ticketReleaseTime,
                ticketCompleteDateTime = record.ticketCompleteDateTime,
                truckLanceCode = record.truckLanceCode,
                shopCode = record.shopCode,
                shopName = record.shopName,
                requiredDeliveryDate = record.requiredDeliveryDate,
                handlerName = record.handlerName,
                numberOfFGItems = countFGItemsFromRecord(record),
                isActiveDoPickOrder = false,
            )
        }

        return (doPickOrderResponses + doPickOrderRecordResponses).sortedByDescending { it.ticketReleaseTime?: LocalDateTime.MIN }
    }

    private fun countFGItems(doPickOrder: DoPickOrder): Int {
        val doPickOrderLines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(doPickOrder.id!!)
        val pickOrderIds = doPickOrderLines.mapNotNull { it.pickOrderId }.distinct()

        if (pickOrderIds.isEmpty()) {
            val directPickOrderId = doPickOrder.pickOrderId
            if (directPickOrderId != null) {
                val pickOrderLines = pickOrderLineRepository.findAllByPickOrderId(directPickOrderId)
                return pickOrderLines.size
            }
            return 0
        }
        val allPickOrderLines = pickOrderIds.flatMap { pickOrderId ->
            pickOrderLineRepository.findAllByPickOrderId(pickOrderId)
        }
        return allPickOrderLines.size
    }

    private fun countFGItemsFromRecord(doPickOrderRecord: DoPickOrderRecord): Int {

        // RECORD_ID FROM DO_PICK_ORDER_RECORD TABLE
        val recordId = doPickOrderRecord.recordId
        if (recordId == null) {
            return 0
        }

        // DO_PICK_ORDER_ID FROM DO_PICK_ORDER_LINE_RECORD TABLE
        val doPickOrderLineRecords = doPickOrderLineRecordRepository.findByDoPickOrderIdAndDeletedFalse(recordId)
        if (doPickOrderLineRecords.isEmpty()) {
            return 0
        }

        // RECORD_ID FROM DO_PICK_ORDER_LINE_RECORD TABLE
        // POID FROM PICK_ORDER_LINE TABLE
        val pickOrderIds = doPickOrderLineRecords.mapNotNull { it.pickOrderId }.distinct()
        if (pickOrderIds.isEmpty()) {
            return 0
        }

        val allPickOrderLines = pickOrderIds.flatMap { pickOrderId ->
            val lines = pickOrderLineRepository.findAllByPickOrderId(pickOrderId)
            lines
        }

        return allPickOrderLines.size
    }

    /**
     * Get truck schedule dashboard data aggregated by store, truck lane, and departure time.
     * Groups DoPickOrder and DoPickOrderRecord data to provide summary statistics.
     */
    open fun getTruckScheduleDashboard(targetDate: LocalDate): List<TruckScheduleDashboardResponse> {
        // Source of truth: delivery_order_pick_order (+ linked pick_order / pick_order_line)
        //
        // NOTE: delivery_order_pick_order 沒有 truckId 欄位；dashboard 的 truckId 目前僅作為展示/鍵值用途，
        // 回傳 null 讓前端保持相容即可。
        val sql = """
            SELECT
              dop.storeId AS storeId,
              dop.truckLanceCode AS truckLanceCode,
              dop.truckDepartureTime AS truckDepartureTime,
              COUNT(DISTINCT dop.shopCode) AS numberOfShopsToServe,
              COUNT(DISTINCT dop.ticketNo) AS numberOfPickTickets,
              COALESCE(SUM(pol_cnt.cnt), 0) AS totalItemsToPick,
              SUM(CASE WHEN dop.ticketReleaseTime IS NOT NULL THEN 1 ELSE 0 END) AS numberOfTicketsReleased,
              MIN(dop.ticketReleaseTime) AS firstTicketStartTime,
              SUM(CASE WHEN dop.ticketCompleteDateTime IS NOT NULL THEN 1 ELSE 0 END) AS numberOfTicketsCompleted,
              MAX(dop.ticketCompleteDateTime) AS lastTicketEndTime
            FROM fpsmsdb.delivery_order_pick_order dop
            LEFT JOIN (
              SELECT
                po.deliveryOrderPickOrderId AS dopId,
                COUNT(pol.id) AS cnt
              FROM fpsmsdb.pick_order po
              INNER JOIN fpsmsdb.pick_order_line pol
                ON pol.poId = po.id
               AND pol.deleted = 0
              WHERE po.deleted = 0
                AND po.deliveryOrderPickOrderId IS NOT NULL
              GROUP BY po.deliveryOrderPickOrderId
            ) pol_cnt
              ON pol_cnt.dopId = dop.id
            WHERE dop.deleted = 0
              AND dop.requiredDeliveryDate = :targetDate
              AND dop.ticketStatus IN ('pending', 'released', 'completed')
            GROUP BY dop.storeId, dop.truckLanceCode, dop.truckDepartureTime
            ORDER BY dop.storeId, dop.truckDepartureTime
        """.trimIndent()

        val rows = jdbcDao.queryForList(sql, mapOf("targetDate" to targetDate))

        fun str(row: Map<String, Any?>, key: String): String? = row[key]?.toString()
        fun intVal(row: Map<String, Any?>, key: String): Int =
            when (val v = row[key]) {
                null -> 0
                is Number -> v.toInt()
                else -> v.toString().toBigDecimalOrNull()?.toInt() ?: 0
            }
        fun timeVal(row: Map<String, Any?>, key: String): java.time.LocalTime? =
            when (val v = row[key]) {
                null -> null
                is java.time.LocalTime -> v
                is java.sql.Time -> v.toLocalTime()
                is java.time.OffsetTime -> v.toLocalTime()
                is String -> runCatching { java.time.LocalTime.parse(v) }.getOrNull()
                else -> null
            }
        fun dtVal(row: Map<String, Any?>, key: String): LocalDateTime? =
            when (val v = row[key]) {
                null -> null
                is LocalDateTime -> v
                is java.sql.Timestamp -> v.toLocalDateTime()
                is String -> runCatching { LocalDateTime.parse(v) }.getOrNull()
                else -> null
            }

        return rows.map { row ->
            val first = dtVal(row, "firstTicketStartTime")
            val last = dtVal(row, "lastTicketEndTime")
            val minutes = if (first != null && last != null) ChronoUnit.MINUTES.between(first, last) else null

            TruckScheduleDashboardResponse(
                storeId = str(row, "storeId"),
                truckId = null,
                truckLanceCode = str(row, "truckLanceCode"),
                truckDepartureTime = timeVal(row, "truckDepartureTime"),
                numberOfShopsToServe = intVal(row, "numberOfShopsToServe"),
                numberOfPickTickets = intVal(row, "numberOfPickTickets"),
                totalItemsToPick = intVal(row, "totalItemsToPick"),
                numberOfTicketsReleased = intVal(row, "numberOfTicketsReleased"),
                firstTicketStartTime = first,
                numberOfTicketsCompleted = intVal(row, "numberOfTicketsCompleted"),
                lastTicketEndTime = last,
                pickTimeTakenMinutes = minutes,
            )
        }
    }
    
    private fun countFGItemsById(doPickOrderId: Long): Int {
        val doPickOrderLines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(doPickOrderId)
        val pickOrderIds = doPickOrderLines.mapNotNull { it.pickOrderId }.distinct()

        if (pickOrderIds.isEmpty()) {
            val doPickOrder = doPickOrderRepository.findById(doPickOrderId).orElse(null)
            val directPickOrderId = doPickOrder?.pickOrderId
            if (directPickOrderId != null) {
                val pickOrderLines = pickOrderLineRepository.findAllByPickOrderId(directPickOrderId)
                return pickOrderLines.size
            }
            return 0
        }
        val allPickOrderLines = pickOrderIds.flatMap { pickOrderId ->
            pickOrderLineRepository.findAllByPickOrderId(pickOrderId)
        }
        return allPickOrderLines.size
    }

    private fun countFGItemsFromRecordById(recordId: Long): Int {
        val doPickOrderLineRecords = doPickOrderLineRecordRepository.findByDoPickOrderIdAndDeletedFalse(recordId)
        if (doPickOrderLineRecords.isEmpty()) {
            return 0
        }

        val pickOrderIds = doPickOrderLineRecords.mapNotNull { it.pickOrderId }.distinct()
        if (pickOrderIds.isEmpty()) {
            return 0
        }

        val allPickOrderLines = pickOrderIds.flatMap { pickOrderId ->
            pickOrderLineRepository.findAllByPickOrderId(pickOrderId)
        }

        return allPickOrderLines.size
    }
    open fun findReleasedDoPickOrdersForSelection(
        shopName: String?,
        storeId: String?,
        truck: String?
    ): List<ReleasedDoPickOrderListItem> {
    
        val today = LocalDate.now()
    
        var filtered = doPickOrderRepository.findByTicketStatusIn(
            listOf(DoPickOrderStatus.released, DoPickOrderStatus.pending)
        )
    
        if (!storeId.isNullOrBlank()) {
            filtered = filtered.filter { it.storeId == storeId }
        }
        if (!shopName.isNullOrBlank()) {
            filtered = filtered.filter {
                it.shopName?.contains(shopName, ignoreCase = true) == true ||
                it.shopCode?.contains(shopName, ignoreCase = true) == true
            }
        }
        if (!truck.isNullOrBlank()) {
            filtered = filtered.filter { it.truckLanceCode == truck }
        }
        filtered = filtered.filter { dpo ->
            dpo.requiredDeliveryDate
                ?.isBefore(today)
                ?: false
        }
        return filtered.map { dpo ->
            val lines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(dpo.id!!)
            val deliveryOrderCodes = lines
                .mapNotNull { it.deliveryOrderCode }
                .distinct()
            
            ReleasedDoPickOrderListItem(
                id = dpo.id!!,
                requiredDeliveryDate = dpo.requiredDeliveryDate,
                shopCode = dpo.shopCode,
                shopName = dpo.shopName,
                storeId = dpo.storeId,
                truckLanceCode = dpo.truckLanceCode,
                truckDepartureTime = dpo.truckDepartureTime,
                deliveryOrderCodes = deliveryOrderCodes.ifEmpty { 
                    listOfNotNull(dpo.deliveryOrderCode) 
                }
            )
        }.sortedWith(
            compareBy<ReleasedDoPickOrderListItem> { it.requiredDeliveryDate }
                .thenBy { it.truckDepartureTime }
                .thenBy { it.truckLanceCode }
        )
    }
    open fun findReleasedDoPickOrdersForSelectionToday(
        shopName: String?,
        storeId: String?,
        truck: String?
    ): List<ReleasedDoPickOrderListItem> {
    
        val today = LocalDate.now()
    
        var filtered = doPickOrderRepository.findByTicketStatusIn(
            listOf(DoPickOrderStatus.released, DoPickOrderStatus.pending)
        )
    
        if (!storeId.isNullOrBlank()) {
            filtered = filtered.filter { it.storeId == storeId }
        }
        if (!shopName.isNullOrBlank()) {
            filtered = filtered.filter {
                it.shopName?.contains(shopName, ignoreCase = true) == true ||
                it.shopCode?.contains(shopName, ignoreCase = true) == true
            }
        }
        if (!truck.isNullOrBlank()) {
            filtered = filtered.filter { it.truckLanceCode == truck }
        }
    
        // 注意：这里是「早于今天」
        filtered = filtered.filter { dpo ->
            dpo.requiredDeliveryDate
                ?.isEqual(today)
                ?: false
        }
    
        return filtered.map { dpo ->
            val lines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(dpo.id!!)
            val deliveryOrderCodes = lines
                .mapNotNull { it.deliveryOrderCode }
                .distinct()
            
            ReleasedDoPickOrderListItem(
                id = dpo.id!!,
                requiredDeliveryDate = dpo.requiredDeliveryDate,
                shopCode = dpo.shopCode,
                shopName = dpo.shopName,
                storeId = dpo.storeId,
                truckLanceCode = dpo.truckLanceCode,
                truckDepartureTime = dpo.truckDepartureTime,
                deliveryOrderCodes = deliveryOrderCodes.ifEmpty { 
                    listOfNotNull(dpo.deliveryOrderCode) 
                }
            )
        }.sortedWith(
            compareBy<ReleasedDoPickOrderListItem> { it.requiredDeliveryDate }
                .thenBy { it.truckDepartureTime }
                .thenBy { it.truckLanceCode }
        )
    }
}//  类结束