package com.ffii.fpsms.modules.deliveryOrder.web

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.service.DeliveryOrderService
import com.ffii.fpsms.modules.deliveryOrder.service.DoReplenishmentService
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 org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import com.ffii.fpsms.modules.deliveryOrder.web.models.DoDetailResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.ExportDNLabelsRequest
import com.ffii.fpsms.modules.deliveryOrder.web.models.ExportDNLabelsReprintRequest
import com.ffii.fpsms.modules.deliveryOrder.web.models.ExportDeliveryNoteRequest
import com.ffii.fpsms.modules.deliveryOrder.web.models.PrintDNLabelsRequest
import com.ffii.fpsms.modules.deliveryOrder.web.models.PrintDNLabelsReprintRequest
import com.ffii.fpsms.modules.deliveryOrder.web.models.PrintDeliveryNoteRequest
import com.ffii.fpsms.modules.deliveryOrder.web.models.ReleaseDoRequest
import com.ffii.fpsms.modules.master.web.models.MessageResponse
import com.ffii.fpsms.modules.stock.web.model.PrintQrCodeForSilRequest
import jakarta.servlet.http.HttpServletResponse
import jakarta.validation.Valid
import net.sf.jasperreports.engine.JasperExportManager
import net.sf.jasperreports.engine.JasperPrint
import org.hibernate.result.Output
import org.springframework.context.NoSuchMessageException
import org.springframework.web.bind.annotation.ModelAttribute
import java.io.OutputStream
import java.io.UnsupportedEncodingException
import java.text.ParseException
import java.time.LocalDateTime
import com.ffii.fpsms.modules.deliveryOrder.web.models.SearchDeliveryOrderInfoRequest
import com.ffii.fpsms.modules.deliveryOrder.service.DoPickOrderService
import com.ffii.core.response.RecordsRes
import com.ffii.fpsms.modules.deliveryOrder.web.models.PrintQrCodeForDoRequest
import com.ffii.fpsms.modules.stock.service.StockInLineService
import com.ffii.fpsms.modules.deliveryOrder.web.models.Check4FTruckBatchResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.DoSearchRowResponse
import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLite
import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLiteDto
import com.ffii.fpsms.modules.deliveryOrder.web.models.DoReplenishmentResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.SubmitDoReplenishmentRequest
import org.slf4j.LoggerFactory
import java.time.LocalDate

@RequestMapping("/do")
@RestController
class DeliveryOrderController(
    private val deliveryOrderService: DeliveryOrderService,
    private val stockInLineService: StockInLineService,
    private val doPickOrderService: DoPickOrderService,
    private val doReplenishmentService: DoReplenishmentService,
) {
    private val log = LoggerFactory.getLogger(javaClass)

    @PostMapping("/search-do-lite")
    fun searchDoLite(@RequestBody request: SearchDeliveryOrderInfoRequest): RecordsRes<DeliveryOrderInfoLiteDto> {
        println("DEBUG: searchDoLite - request: code=${request.code}, shopName=${request.shopName}, status=${request.status}")
        println("DEBUG: searchDoLite - estimatedArrivalDate=${request.estimatedArrivalDate}")
        println("DEBUG: searchDoLite - truckLanceCode=${request.truckLanceCode}")  // 添加这行
        println("DEBUG: searchDoLite - pagination: pageNum=${request.pageNum}, pageSize=${request.pageSize}")
        
        return deliveryOrderService.searchDoLiteByPage(
            code = request.code,
            shopName = request.shopName,
            status = request.status,
            estimatedArrivalDate = request.estimatedArrivalDate,
            pageNum = request.pageNum,
            pageSize = request.pageSize,
            truckLanceCode = request.truckLanceCode,
            floor = request.floor,
            isExtra = request.isExtra,
        )
    }

    /**
     * 僅回傳推算車線為 null／空白之送貨單（對應 UI 車線-X）。請求體與 search-do-lite 相同，**忽略** [SearchDeliveryOrderInfoRequest.truckLanceCode]。
     */
    @PostMapping("/search-do-lite-unassigned-truck")
    fun searchDoLiteUnassignedTruck(@RequestBody request: SearchDeliveryOrderInfoRequest): RecordsRes<DeliveryOrderInfoLiteDto> {
        return deliveryOrderService.searchDoLiteUnassignedTruckByPage(
            code = request.code,
            shopName = request.shopName,
            status = request.status,
            estimatedArrivalDate = request.estimatedArrivalDate,
            pageNum = request.pageNum,
            pageSize = request.pageSize,
            floor = request.floor,
            isExtra = request.isExtra,
        )
    }

    /**
     * DO 輕量搜索 v2：車線關鍵字正規化（`車線-X`／`x`／`車線-` 前綴併入未指派）、
     * 允許供應商條件下分批掃描，避免單次載入過大；請求體同 [searchDoLite]。
     */
    @PostMapping("/search-do-lite-v2")
    fun searchDoLiteV2(@RequestBody request: SearchDeliveryOrderInfoRequest): RecordsRes<DeliveryOrderInfoLiteDto> {
        return deliveryOrderService.searchDoLiteByPageV2(
            code = request.code,
            shopName = request.shopName,
            status = request.status,
            estimatedArrivalDate = request.estimatedArrivalDate,
            pageNum = request.pageNum,
            pageSize = request.pageSize,
            truckLanceCode = request.truckLanceCode,
            floor = request.floor,
            isExtra = request.isExtra,
        )
    }

    @GetMapping("/list")
    fun getDoList(): List<DeliveryOrderInfo> {
        return deliveryOrderService.getDoList();
    }

    @GetMapping("/detail/{id}")
    fun getDetailedDo(@PathVariable id: Long): DoDetailResponse? {
        return deliveryOrderService.getDetailedDo(id);
    }

    @PostMapping("/replenishment")
    fun submitReplenishment(
        @Valid @RequestBody request: SubmitDoReplenishmentRequest,
    ): List<DoReplenishmentResponse> {
        return doReplenishmentService.submit(request)
    }

    @GetMapping("/replenishment")
    fun listReplenishment(
        @RequestParam(required = false) deliveryDate: LocalDate?,
        @RequestParam(required = false) status: String?,
    ): List<DoReplenishmentResponse> {
        return doReplenishmentService.list(deliveryDate, status)
    }

    @GetMapping("/replenishment/for-batch-release")
    fun listReplenishmentForBatchRelease(
        @RequestParam(required = false) truckLaneCode: String?,
        @RequestParam(required = false) shopName: String?,
    ): List<DoReplenishmentResponse> {
        return doReplenishmentService.listForBatchRelease(truckLaneCode, shopName)
    }

    @GetMapping("/search-code/{code}")
    fun searchByCode(@PathVariable code: String): List<DeliveryOrderInfo> {
        return deliveryOrderService.searchByCode(code);
    }

    @GetMapping("/search-shopname/{shopName}")
    fun searchByShopName(@PathVariable shopName: String): List<DeliveryOrderInfo> {
        return deliveryOrderService.searchByShopName(shopName);
    }

    @GetMapping("/search-status/{status}")
    fun searchByStatus(@PathVariable status: DeliveryOrderStatus): List<DeliveryOrderInfo> {
        return deliveryOrderService.searchByStatus(status);
    }

    @GetMapping("/search-orderdate/{start}&{end}")
    fun searchBetweenOrderDate(
        @PathVariable start: LocalDateTime?,
        @PathVariable end: LocalDateTime?
    ): List<DeliveryOrderInfo> {
        return deliveryOrderService.searchBetweenOrderDate(start, end);
    }

    @GetMapping("/search-DO/{code}&{shopName}&{status}&{orderStartDate}&{orderEndDate}&{estArrStartDate}&{estArrEndDate}")
    fun searchDO(
        @PathVariable code: String?,
        @PathVariable shopName: String?,
        @PathVariable status: DeliveryOrderStatus?,
        @PathVariable orderStartDate: LocalDateTime?,
        @PathVariable orderEndDate: LocalDateTime?,
        @PathVariable estArrStartDate: LocalDateTime?,
        @PathVariable estArrEndDate: LocalDateTime?
    ): List<DeliveryOrderInfo> {
        println("test");
        if (code != null || shopName != null) {
            if (orderStartDate != null && orderEndDate != null && estArrStartDate != null && estArrEndDate != null) {
                if (status != null) {
                    return deliveryOrderService.searchAll(
                        code,
                        shopName,
                        status,
                        orderStartDate,
                        orderEndDate,
                        estArrStartDate,
                        estArrEndDate
                    );
                } else {
                    return deliveryOrderService.searchWithoutStatus(
                        code,
                        shopName,
                        orderStartDate,
                        orderEndDate,
                        estArrStartDate,
                        estArrEndDate
                    );
                }
            } else {
                if (orderStartDate == null && orderEndDate == null && estArrStartDate == null && estArrEndDate == null) {
                    if (status != null) {
                        return deliveryOrderService.searchWithoutDate(code, shopName, status);
                    } else {
                        return deliveryOrderService.searchCodeAndShopName(code, shopName);
                    }
                } else {
                    if (estArrStartDate != null && estArrEndDate != null && (orderStartDate == null && orderEndDate == null)) {
                        if (status != null) {
                            return deliveryOrderService.searchWithoutOrderDate(
                                code,
                                shopName,
                                status,
                                estArrStartDate,
                                estArrEndDate
                            );
                        } else {
                            return deliveryOrderService.searchWithoutOrderDateAndStatus(
                                code,
                                shopName,
                                estArrStartDate,
                                estArrEndDate
                            );
                        }
                    } else if (orderStartDate != null && orderEndDate != null && (estArrStartDate == null && estArrEndDate == null)) {
                        if (status != null) {
                            return deliveryOrderService.searchAll(
                                code,
                                shopName,
                                status,
                                orderStartDate,
                                orderEndDate,
                                estArrStartDate,
                                estArrEndDate
                            );
                        } else {
                            return deliveryOrderService.searchWithoutStatus(
                                code,
                                shopName,
                                orderStartDate,
                                orderEndDate,
                                estArrStartDate,
                                estArrEndDate
                            );
                        }
                    } else {
                        return emptyList();
                    }
                }

            }
        }
        return deliveryOrderService.getFullList();


    }

    @PostMapping("/update-status")
    fun updateDoStatus(@RequestBody request: SaveDeliveryOrderStatusRequest): SaveDeliveryOrderResponse {
        return deliveryOrderService.updateDeliveryOrderStatus(request);
    }

    @PostMapping("/start")
    fun startDo(@RequestBody id: Long): SaveDeliveryOrderResponse {
        val request = SaveDeliveryOrderStatusRequest(
            id = id,
            status = DeliveryOrderStatus.RECEIVING.value
        )
        return deliveryOrderService.updateDeliveryOrderStatus(request);
    }

    @PostMapping("/release")
    fun releaseDeliveryOrder(@RequestBody request: ReleaseDoRequest): MessageResponse {
        //  Simply pass the request directly - userId comes from frontend session
        return deliveryOrderService.releaseDeliveryOrder(request)
    }

    @PostMapping("/DN")
    @Throws(UnsupportedEncodingException::class, NoSuchMessageException::class, ParseException::class, Exception::class)
    fun printDN(@Valid @RequestBody request: ExportDeliveryNoteRequest, response: HttpServletResponse){
        val t0 = System.nanoTime()
        response.characterEncoding = "utf-8"
        response.contentType = "application/pdf"
        val out: OutputStream = response.outputStream
        val pdf = deliveryOrderService.exportDeliveryNote(request)
        val jasperPrint = pdf["report"] as JasperPrint
        response.addHeader("filename", "${pdf["filename"]}.pdf")
        val t1 = System.nanoTime()
        val bytes = JasperExportManager.exportReportToPdf(jasperPrint)
        val jasperExportToPdfBytesMs = (System.nanoTime() - t1) / 1_000_000.0
        out.write(bytes)
        val totalHttpMs = (System.nanoTime() - t0) / 1_000_000.0
        log.info(
            "DeliveryNote POST /do/DN (download) timing: jasperExportToPdfBytesMs={} totalResponseMs={} doPickOrderId={} isDraft={}",
            jasperExportToPdfBytesMs,
            totalHttpMs,
            request.doPickOrderId,
            request.isDraft,
        )
    }

    @GetMapping("/print-DN")
    fun printDN(@ModelAttribute request: PrintDeliveryNoteRequest) {
        deliveryOrderService.printDeliveryNote(request)
    }

    @PostMapping("/DNLabels")
    @Throws(UnsupportedEncodingException::class, NoSuchMessageException::class, ParseException::class, Exception::class)
    fun printDNLabels(@Valid @RequestBody request: ExportDNLabelsRequest, response: HttpServletResponse){
        response.characterEncoding = "utf-8"
        response.contentType = "application/pdf"
        val out: OutputStream = response.outputStream
        val pdf = deliveryOrderService.exportDNLabels(request)
        val jasperPrint = pdf["report"] as JasperPrint
        response.addHeader("filename", "${pdf["filename"]}.pdf")
        out.write(JasperExportManager.exportReportToPdf(jasperPrint))
    }

    @GetMapping("print-DNLabels")
    fun printDN(@ModelAttribute request: PrintDNLabelsRequest) {
        deliveryOrderService.printDNLabels(request)
    }

    @PostMapping("/DNLabels/reprint")
    @Throws(UnsupportedEncodingException::class, NoSuchMessageException::class, ParseException::class, Exception::class)
    fun printDNLabelsReprint(
        @Valid @RequestBody request: ExportDNLabelsReprintRequest,
        response: HttpServletResponse
    ) {
        response.characterEncoding = "utf-8"
        response.contentType = "application/pdf"
        val out: OutputStream = response.outputStream
        val pdf = deliveryOrderService.exportDNLabelsReprint(request)
        val jasperPrint = pdf["report"] as JasperPrint
        response.addHeader("filename", "${pdf["filename"]}.pdf")
        out.write(JasperExportManager.exportReportToPdf(jasperPrint))
    }

    @GetMapping("print-DNLabels-reprint")
    fun printDNLabelsReprint(@ModelAttribute request: PrintDNLabelsReprintRequest) {
        deliveryOrderService.printDNLabelsReprint(request)
    }

    @GetMapping("/batchPrintQrCode")
    fun printQrCodeForDeliveryOrder(@ModelAttribute request: PrintQrCodeForDoRequest) {
        stockInLineService.printQrCodeForDeliveryOrder(request)
    }
    @PostMapping("/check-4f-trucks-batch")
    fun check4FTrucksBatch(@RequestBody doIds: List<Long>): Check4FTruckBatchResponse {
        return deliveryOrderService.check4FTruckAvailabilityForDoList(doIds)
    }
}