package com.ffii.fpsms.modules.stock.web

import com.ffii.core.response.RecordsRes
import com.ffii.fpsms.modules.pickOrder.web.models.ConsoPickOrderRequest
import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository
import com.ffii.fpsms.modules.stock.entity.StockInLineRepository
import com.ffii.fpsms.modules.stock.entity.projection.InventoryLotLineInfo
import com.ffii.fpsms.modules.stock.entity.projection.LotLineToQrcode
import com.ffii.fpsms.modules.stock.service.InventoryLotLineService
import com.ffii.fpsms.modules.stock.service.StockInLineService
import com.ffii.fpsms.modules.stock.web.model.ExportQrCodeRequest
import com.ffii.fpsms.modules.stock.web.model.LotLineInfo
import com.ffii.fpsms.modules.stock.web.model.SearchInventoryLotLineInfoRequest
import com.ffii.fpsms.modules.stock.web.model.UpdateInventoryLotLineQuantitiesRequest
import jakarta.servlet.http.HttpServletResponse
import jakarta.validation.Valid
import net.sf.jasperreports.engine.JasperExportManager
import net.sf.jasperreports.engine.JasperPrint
import org.springframework.context.NoSuchMessageException
import org.springframework.web.bind.annotation.*
import java.io.OutputStream
import java.io.UnsupportedEncodingException
import java.math.BigDecimal
import java.text.ParseException
import com.ffii.fpsms.modules.master.web.models.MessageResponse
import com.ffii.fpsms.modules.stock.web.model.PrintLabelForInventoryLotLineRequest
import com.ffii.fpsms.modules.stock.web.model.UpdateInventoryLotLineStatusRequest
import com.ffii.fpsms.modules.stock.web.model.QrCodeAnalysisRequest
import com.ffii.fpsms.modules.stock.web.model.QrCodeAnalysisResponse
import com.ffii.fpsms.modules.stock.web.model.WorkbenchItemLotsResponse
import org.springframework.http.HttpStatus
import org.springframework.web.server.ResponseStatusException

@RequestMapping("/inventoryLotLine")
@RestController
class InventoryLotLineController (
    private val inventoryLotLineRepository: InventoryLotLineRepository,
    private val inventoryLotLineService: InventoryLotLineService,
    private val stockInLineRepository: StockInLineRepository,
    private val stockInLineService: StockInLineService,

){
//    @PostMapping("/test")
//    fun test(@Valid @RequestBody request: ConsoPickOrderRequest) :Any {
//        return inventoryLotLineRepository.findInventoryLotLineInfoByInventoryLotItemIdIn(request.ids)
//    }
    @PostMapping("/test")
    fun test(@Valid @RequestBody request: ConsoPickOrderRequest): Any {
        return inventoryLotLineRepository.findCurrentInventoryByItems(request.ids)
    }

    @GetMapping("/getRecordByPage")
    fun allInventoryLotLinesByPage(@ModelAttribute request: SearchInventoryLotLineInfoRequest): RecordsRes<InventoryLotLineInfo> {
//        println(request.itemId)
        return inventoryLotLineService.allInventoryLotLinesByPage(request);
    }

    @GetMapping("/lot-detail/{stockInLineId}")
    fun getLotDetail(@Valid @PathVariable stockInLineId: Long): LotLineInfo {
        val stockInLine = stockInLineRepository.findById(stockInLineId).orElseThrow {
            ResponseStatusException(HttpStatus.NOT_FOUND, "stockInLineId $stockInLineId not found")
        }
        val inventoryLotLine = stockInLine.inventoryLotLine!!
        val zero = BigDecimal.ZERO
        return LotLineInfo(
            inventoryLotLineId = inventoryLotLine.id!!,
            itemId = inventoryLotLine.inventoryLot!!.item!!.id!!,
            itemNo = inventoryLotLine.inventoryLot!!.item!!.code!!,
            itemName = inventoryLotLine.inventoryLot!!.item!!.name!!,
            lotNo = stockInLine.lotNo!!,
            remainingQty = (inventoryLotLine.inQty ?: zero)
                .minus(inventoryLotLine.outQty ?: zero)
                .minus(inventoryLotLine.holdQty ?: zero),
            uom = inventoryLotLine.stockUom!!.uom!!.udfudesc!!
        )
    }

    @PostMapping("/download-label")
    @Throws(UnsupportedEncodingException::class, NoSuchMessageException::class, ParseException::class, Exception::class)
    fun printLabel(@Valid @RequestBody request: LotLineToQrcode, response: HttpServletResponse) {
        response.characterEncoding = "utf-8";
        response.contentType = "application/pdf";
        val out: OutputStream = response.outputStream
        val pdf = inventoryLotLineService.exportLabelForInventoryLotLine(request.inventoryLotLineId)
        val jasperPrint = pdf["report"] as JasperPrint
        response.addHeader("filename", "${pdf["fileName"]}.pdf")
        out.write(JasperExportManager.exportReportToPdf(jasperPrint));
    }

    @GetMapping("/print-label")
    fun printLabel(@ModelAttribute request: PrintLabelForInventoryLotLineRequest) {
        inventoryLotLineService.printLabelForInventoryLotLine(request)
    }

    /**
     * Workbench print endpoint: same printing behavior as `/print-label`,
     * but always returns JSON so frontend won't fail on empty-body JSON parsing.
     */
    @GetMapping("/workbench/print-label")
    fun printLabelWorkbench(@ModelAttribute request: PrintLabelForInventoryLotLineRequest): MessageResponse {
        return try {
            inventoryLotLineService.printLabelForInventoryLotLine(request)
            MessageResponse(
                id = request.inventoryLotLineId,
                name = "print_label",
                code = "SUCCESS",
                type = "workbench_print_label",
                message = "Print job submitted",
                errorPosition = null,
            )
        } catch (e: Exception) {
            MessageResponse(
                id = request.inventoryLotLineId,
                name = "print_label",
                code = "ERROR",
                type = "workbench_print_label",
                message = e.message ?: "Print failed",
                errorPosition = null,
            )
        }
    }

    @PostMapping("/updateStatus")
    fun updateInventoryLotLineStatus(@RequestBody request: UpdateInventoryLotLineStatusRequest): MessageResponse {
        println("=== DEBUG: updateInventoryLotLineStatus Controller ===")
        println("Request received: $request")
        println("inventoryLotLineId: ${request.inventoryLotLineId}")
        println("status: ${request.status}")
        
        try {
            val result = inventoryLotLineService.updateInventoryLotLineStatus(request)
            println(" Controller: Update successful - $result")
            return result
        } catch (e: Exception) {
            println("❌ Controller: Update failed - ${e.message}")
            e.printStackTrace()
            throw e
        }
    }

    @PostMapping("/updateQuantities")
    fun updateInventoryLotLineQuantities(@RequestBody request: UpdateInventoryLotLineQuantitiesRequest): MessageResponse {
        return inventoryLotLineService.updateInventoryLotLineQuantities(request)
    }
    @PostMapping("/analyze-qr-code")
    fun analyzeQrCode(@RequestBody request: QrCodeAnalysisRequest): QrCodeAnalysisResponse {
        return inventoryLotLineService.analyzeQrCode(request)
    }

    /** DO workbench label modal: same-item lots use pickable qty inQty - outQty (no hold). */
    @PostMapping("/workbench/analyze-qr-code")
    fun analyzeQrCodeWorkbench(@RequestBody request: QrCodeAnalysisRequest): QrCodeAnalysisResponse {
        return inventoryLotLineService.analyzeQrCodeWorkbench(request)
    }

    /** Workbench label modal fallback: load same-item available lots without stockInLineId. */
    @GetMapping("/workbench/available-lots-by-item/{itemId}")
    fun listWorkbenchAvailableLotsByItem(@PathVariable itemId: Long): WorkbenchItemLotsResponse {
        return inventoryLotLineService.listWorkbenchAvailableLotsByItem(itemId)
    }
}