package com.ffii.core.utils

import org.apache.pdfbox.pdmodel.PDDocument
import org.apache.pdfbox.rendering.PDFRenderer
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.OutputStream
import java.net.Socket
import javax.imageio.ImageIO

class BrotherPrinterUtil {

    companion object {
        /**
         * //Usage 
         * BrotherPrinterUtil.printToBrother(
                pdfFile = File("document.pdf"),
                printerIp = "192.168.1.50",
                printQty = 1
            )

         * Sends a PDF to a Brother DCP-1610W by rendering it to a PCL-compatible format.
         */
        fun printToBrother(pdfFile: File, printerIp: String, printerPort: Int = 9100, printQty: Int = 1) {
            if (!pdfFile.exists()) throw IllegalArgumentException("File not found.")

            PDDocument.load(pdfFile).use { document ->
                val renderer = PDFRenderer(document)
                
                Socket(printerIp, printerPort).use { socket ->
                    val os = socket.getOutputStream()
                    
                    // 1. Start PJL Job
                    os.write(getPjlHeader(printQty))

                    // 2. Render each page as a 300 DPI image
                    for (pageIndex in 0 until document.numberOfPages) {
                        val image = renderer.renderImageWithDPI(pageIndex, 300f, org.apache.pdfbox.rendering.ImageType.BINARY)
                        
                        // 3. Convert Image to PCL Raster Data
                        val pclData = convertImageToPcl(image)
                        os.write(pclData)
                        
                        // Form Feed (Move to next page)
                        os.write("\u000C".toByteArray()) 
                    }

                    // 4. End Job
                    os.write("\u001B%-12345X".toByteArray(Charsets.US_ASCII))
                    os.flush()
                }
            }
        }

        private fun getPjlHeader(qty: Int): ByteArray {
            val pjl = StringBuilder()
            pjl.append("\u001B%-12345X@PJL\r\n")
            pjl.append("@PJL SET COPIES=$qty\r\n")
            pjl.append("@PJL ENTER LANGUAGE=PCL\r\n") // Tell printer to expect PCL graphics, not PDF
            return pjl.toString().toByteArray(Charsets.US_ASCII)
        }

        /**
         * Converts a BufferedImage into PCL Level 3/5 Raster Graphics.
         * This is the "magic" that allows a budget printer to print a PDF.
         */
        private fun convertImageToPcl(image: BufferedImage): ByteArray {
            val out = ByteArrayOutputStream()
            val width = image.width
            val height = image.height

            // PCL: Start Graphics at 300 DPI
            out.write("\u001B*t300R".toByteArray()) 
            // PCL: Start Raster Graphics
            out.write("\u001B*r1A".toByteArray()) 

            for (y in 0 until height) {
                val rowBytes = (width + 7) / 8
                val data = ByteArray(rowBytes)
                
                for (x in 0 until width) {
                    // Check if pixel is dark (threshold)
                    val color = image.getRGB(x, y)
                    val isBlack = (color and 0xFF) < 128 
                    if (isBlack) {
                        data[x / 8] = (data[x / 8].toInt() or (0x80 ushr (x % 8))).toByte()
                    }
                }
                
                // PCL: Transfer Raster Data (Esc * b # W [data])
                out.write("\u001B*b${rowBytes}W".toByteArray())
                out.write(data)
            }

            // PCL: End Raster Graphics
            out.write("\u001B*rB".toByteArray())
            return out.toByteArray()
        }
    }
}