package com.ffii.fpsms.modules.master.service

import com.ffii.core.utils.PdfUtils
import com.ffii.core.utils.QrCodeUtil
import com.ffii.fpsms.modules.master.print.A4PrintDriverRegistry
import com.ffii.fpsms.modules.master.entity.WarehouseRepository
import com.ffii.fpsms.modules.master.web.ExportWarehouseQrCodeRequest
import com.ffii.fpsms.modules.master.web.PrintWarehouseQrCodeRequest
import net.sf.jasperreports.engine.JasperCompileManager
import net.sf.jasperreports.engine.JasperExportManager
import net.sf.jasperreports.engine.JasperReport
import net.sf.jasperreports.engine.JasperPrint
import org.springframework.core.io.ClassPathResource
import org.springframework.stereotype.Service
import java.io.File
import java.io.FileNotFoundException
import java.awt.GraphicsEnvironment
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString

@Service
class WarehouseQrCodeService(
    private val warehouseRepository: WarehouseRepository,
    private val printerService: PrinterService,
) {
    private val qrCodeHandleJrxmlPath = "qrCodeHandle/warehouse_QrHandle.jrxml"

    /** Compile the Jasper template once; compiling per request is expensive. */
    private val qrCodeHandleReport: JasperReport by lazy {
        val resource = ClassPathResource(qrCodeHandleJrxmlPath)
        if (!resource.exists()) {
            throw FileNotFoundException("Report file not found: $qrCodeHandleJrxmlPath")
        }
        resource.inputStream.use { JasperCompileManager.compileReport(it) }
    }

    /** Cache the chosen Chinese font family name (font scanning is expensive). */
    private val chineseFontFamily: String by lazy {
        val availableFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().availableFontFamilyNames
        availableFonts.find { family ->
            family.contains("SimSun", ignoreCase = true) ||
                family.contains("Microsoft YaHei", ignoreCase = true) ||
                family.contains("STSong", ignoreCase = true) ||
                family.contains("SimHei", ignoreCase = true)
        } ?: "Arial Unicode MS"
    }

    fun exportWarehouseQrCode(request: ExportWarehouseQrCodeRequest): Map<String, Any> {
        val warehouses = warehouseRepository.findAllById(request.warehouseIds)
        if (warehouses.isEmpty()) {
            throw IllegalArgumentException("No warehouses found for the provided warehouse IDs: ${request.warehouseIds}")
        }
        
        val fields = mutableListOf<MutableMap<String, Any>>()
        
        for (warehouse in warehouses) {
            val field = mutableMapOf<String, Any>()
            
            val code = warehouse.code ?: ""
            
            if (code.isBlank()) {
                continue
            }
            
            val warehouseId = warehouse.id
            if (warehouseId == null) {
            continue  
            }
    
            val qrContentMap = mapOf("warehouseId" to warehouseId) 
            val qrCodeContent = Json.encodeToString(qrContentMap).replace(Regex("""(?<!:)(:)(?!\s)"""), ": ")
            
            val qrCodeImage = QrCodeUtil.generateQRCodeImage(qrCodeContent)
            
            field["username"] = ""
            field["staffNo"] = ""
            field["code"] = code
            field["equipmentCode"] = ""
            field["qrCode"] = qrCodeImage
            
            fields.add(field)
        }
        
        if (fields.isEmpty()) {
            throw IllegalArgumentException("No valid warehouses found for the provided warehouse IDs: ${request.warehouseIds}")
        }
        
        val params: MutableMap<String, Any> = mutableMapOf()

        params["net.sf.jasperreports.default.pdf.encoding"] = "Identity-H"
        params["net.sf.jasperreports.default.pdf.embedded"] = true
        params["net.sf.jasperreports.default.pdf.font.name"] = chineseFontFamily
        
        val firstWarehouse = warehouses.firstOrNull()
        
        return mapOf(
            "report" to PdfUtils.fillReport(qrCodeHandleReport, fields, params),
            "fileName" to (firstWarehouse?.code ?: "warehouse_qrcode")
        )
    }

    fun printWarehouseQrCode(request: PrintWarehouseQrCodeRequest) {
        val printer = printerService.findById(request.printerId) ?: throw NoSuchElementException("No such printer")
        val pdf = exportWarehouseQrCode(ExportWarehouseQrCodeRequest(request.warehouseIds))
        val jasperPrint = pdf["report"] as JasperPrint
        val tempPdfFile = File.createTempFile("print_job_", ".pdf")

        try {
            JasperExportManager.exportReportToPdfFile(jasperPrint, tempPdfFile.absolutePath)
            val printQty = if (request.printQty == null || request.printQty <= 0) 1 else request.printQty
            printer.ip?.let { ip ->
                val port = printer.port ?: 9100
                val driver = A4PrintDriverRegistry.getDriver(printer.brand)
                driver.print(tempPdfFile, ip, port, printQty)
            }
        } finally {
            tempPdfFile.delete()
        }
    }
}
