package com.lukouguoji.module_base.util

import android.Manifest
import android.graphics.Typeface
import com.gainscha.sdk2.ConnectType
import com.gainscha.sdk2.ConnectionListener
import com.gainscha.sdk2.Printer
import com.gainscha.sdk2.PrinterFinder
import com.gainscha.sdk2.command.Tspl
import com.gainscha.sdk2.model.BluetoothPrinterDevice
import com.gainscha.sdk2.model.Instruction
import com.gainscha.sdk2.v
import com.gprinter.bean.PrinterDevices
import com.gprinter.command.LabelCommand
import com.gprinter.io.BluetoothPort
import com.gprinter.io.PortManager
import com.gprinter.utils.CallbackListener
import com.gprinter.utils.Command
import com.gprinter.utils.ConnMethod
import com.lukouguoji.module_base.bean.GjcUldUseBean
import com.lukouguoji.module_base.bean.GncFuBangBean
import com.lukouguoji.module_base.bean.GncShouYunBean
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.loge
import com.lukouguoji.module_base.ktx.permission
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.model.LoadingModel
import dev.DevUtils
import okio.internal.commonToUtf8String


object PrinterUtils {

    /**
     * 打印单元格数据
     */
    private data class CellData(
        val title: String,       // 中文标签（大字）
        val subtitle: String,    // 英文标签（小字）
        val value: String        // 值（大字，垂直居中）
    )

    /**
     * 打印表格行数据
     */
    private data class GridRow(
        val left: CellData? = null,
        val right: CellData? = null,
        val merged: CellData? = null  // 合并单元格数据
    )

    private val loading by lazy {
        LoadingModel()
    }

    private val finder by lazy {
        PrinterFinder()
    }

    var portManager: PortManager? = null

    private val callBackListener = object : CallbackListener {
        override fun onConnecting() {
            showLog("onConnecting")
        }

        override fun onCheckCommand() {
            showLog("onCheckCommand")
        }

        override fun onSuccess(printerDevices: PrinterDevices?) {
            loading.dismissLoading()
            showLog("onSuccess ${printerDevices?.blueName}")
            showToast("连接${printerDevices?.blueName}成功")
            callBack?.invoke(true)
        }

        override fun onReceive(data: ByteArray?) {
            showLog("onReceive : ${data?.commonToUtf8String()}")
        }

        override fun onFailure() {
            loading.dismissLoading()
            showLog("onFailure")
            showToast("连接蓝牙打印机失败")
            callBack?.invoke(false)
        }

        override fun onDisconnect() {
            showLog("onDisconnect")
            showToast("蓝牙打印机断开连接")
        }

    }

    private var callBack: ((Boolean) -> Unit)? = null

    ///////////////////////////////////////////////////////////////////////////
    // 方法区
    ///////////////////////////////////////////////////////////////////////////

    init {
        Printer.addConnectionListener(object : ConnectionListener {
            override fun onPrinterConnected(printer: Printer) {
                val printerName = printer.printerDevice.printerName
                showLog("打印机连接 $printerName - 成功")
                loading.dismissLoading()
                showToast("连接${printerName}成功")
                callBack?.invoke(true)
            }

            override fun onPrinterConnectFail(printer: Printer) {
                loading.dismissLoading()
                val printerName = printer.printerDevice.printerName
                showLog("打印机连接 $printerName - 失败")
                showToast("连接${printerName}失败")
                callBack?.invoke(false)
            }

            override fun onPrinterDisconnect(printer: Printer) {
                val printerName = printer.printerDevice.printerName
                showLog("打印机断开连接 - $printerName")
                showToast("${printerName}断开连接")
            }
        })
    }

    /**
     * 查找并回调
     */
    fun searchCallBack(callBack: (Boolean) -> Unit) {
        portManager?.printerDevices?.blueName
        if (portManager != null && portManager?.connectStatus == true) {
            callBack.invoke(true)
        } else {
            callBack.invoke(false)
        }
    }

    /**
     * 搜索打印机
     */
    fun searchPrinters(callBack: (PrinterDevices) -> Unit) {
        DevUtils.getTopActivity()
            .permission(
                Manifest.permission.BLUETOOTH,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
            ) {
                finder.searchPrinters(
                    ConnectType.BLUETOOTH,
                    object : PrinterFinder.SimpleSearchPrinterResultListener() {
                        override fun onSearchBluetoothPrinter(device: BluetoothPrinterDevice?) {
                            if (device == null) return
                            showLog("搜索到蓝牙设备 ${device.printerName}")
                            val devices = PrinterDevices.Build()
                                .setContext(DevUtils.getTopActivity())
                                .setConnMethod(ConnMethod.BLUETOOTH)
                                .setMacAddress(device.bluetoothDevice.address)
                                .setCommand(Command.TSC)
                                .setCallbackListener(callBackListener)
                                .setBlueName(device.printerName)
                                .build()
                            callBack.invoke(devices)
                        }

                        override fun onSearchCompleted() {
                            showLog("onSearchCompleted")
                        }
                    })
            }
    }

    /**
     * 连接
     */
    fun connect(devices: PrinterDevices, callBack: (Boolean) -> Unit) {
        this.callBack = callBack
        // 关闭之前连接
        portManager?.closePort()
        // 创建连接
        portManager = BluetoothPort(devices)
        portManager?.openPort()
    }

    /**
     * 断开连接
     */
    fun disconnect() {
        portManager?.closePort()
        portManager = null
    }

    fun printBox() {
        val bytes = Tspl().apply {
            addSize(100, 100)
            addGap(0)
            addCls()
            addBox(10, 10, 1150, 1150, 10)
            addPrint(1)
        }.bytes
        portManager?.writeDataImmediately(bytes)
    }

    /**
     * 打印平板车二维码
     */
    fun printCar(car: String) {
        val bytes = Tspl().apply {
            addSize(80, 60)
            addGap(3)
            addCls()
            addText(420, 30, Tspl.FONT_TSS24, 0, 2, 2, car)
            addQRCode(200, 100, Tspl.BARCODE_ERROR_LEVEL_HEIGHT, 25, 0, car)
            addPrint(1)
        }.bytes

        portManager?.writeDataImmediately(bytes)
    }

    /**
     * 打印收运挂签
     */
    fun printShouYun(bean: GncShouYunBean) {
        val rowItem = arrayListOf<List<String>>()

//        rowItem.add(listOf("日期", bean.fdate, "航班号", bean.fno, "目的站", bean.dest))
//        rowItem.add(listOf("斗号", bean.location, "计重", bean.username, "仓管", ""))
//        rowItem.add(listOf("装机仓位", "", "机位", "", "特车司机", ""))
//        rowItem.add(listOf("监装监卸", "", "中转信息", "", "备注", ""))

        var destinationCn = ""
        var fDestinationCn = ""
        launchCollect({
            NetApply.api.getAirportByCode(bean.dest1)
        }) {
            onSuccess = {
                destinationCn = it.data?.nameCn ?: ""
                rowItem.add(listOf("日期", "航班号", "目的站"))
                rowItem.add(listOf(bean.fdate, bean.fno, bean.dest1 + destinationCn))
                rowItem.add(listOf("斗号", "计重", "仓管"))
                rowItem.add(listOf(bean.location, bean.username, ""))
                rowItem.add(listOf("装机仓位", "机位", "特车司机"))
                rowItem.add(listOf("", "", ""))
                rowItem.add(listOf("监装监卸", "中转信息", "备注"))
                if (bean.dest2 != "") {
                    launchCollect({
                        NetApply.api.getAirportByCode(bean.dest2)
                    }) {
                        onSuccess = { it2 ->
                            fDestinationCn = it2.data?.nameCn ?: ""
                            rowItem.add(listOf("", bean.dest2 + fDestinationCn, ""))
                            printCommonGridNew(rowItem)
                        }
                    }
                } else {
                    rowItem.add(listOf("", "", ""))
                    printCommonGridNew(rowItem)
                }
            }
        }
    }

    // 打印复磅标签
    fun printFuBang(bean: GncFuBangBean) {
        val rowItem = arrayListOf<List<String>>()

//        rowItem.add(listOf("日期", bean.fdate, "航班号", bean.fno, "目的站", bean.fdest))
//        rowItem.add(listOf("斗号", bean.carId, "计重", bean.username, "仓管", ""))
//        rowItem.add(listOf("装机仓位", "", "机位", "", "特车司机", ""))
//        rowItem.add(listOf("监装监卸", "", "中转信息", "", "备注", ""))

        var destinationCn = ""
        var fDestinationCn = ""
        launchCollect({
            NetApply.api.getAirportByCode(bean.fdest)
        }) {
            onSuccess = {
                fDestinationCn = it.data?.nameCn ?: ""
                if (bean.dest != "") {
                    launchCollect({
                        NetApply.api.getAirportByCode(bean.dest)
                    }) {
                        onSuccess = { it2 ->
                            destinationCn = it2.data?.nameCn ?: ""
                            rowItem.add(listOf("日期", "航班号", "目的站"))
                            rowItem.add(listOf(bean.fdate, bean.fno, bean.fdest + fDestinationCn))
                            rowItem.add(listOf("斗号", "计重", "仓管"))
                            rowItem.add(listOf(bean.location, bean.username, ""))
                            rowItem.add(listOf("装机仓位", "机位", "特车司机"))
                            rowItem.add(listOf("", "", ""))
                            rowItem.add(listOf("监装监卸", "中转信息", "备注"))
                            rowItem.add(listOf("", bean.dest + destinationCn, ""))
                            printCommonGridNew(rowItem)
                        }
                    }
                } else {
                    rowItem.add(listOf("日期", "航班号", "目的站"))
                    rowItem.add(listOf(bean.fdate, bean.fno, bean.fdest + fDestinationCn))
                    rowItem.add(listOf("斗号", "计重", "仓管"))
                    rowItem.add(listOf(bean.location, bean.username, ""))
                    rowItem.add(listOf("装机仓位", "机位", "特车司机"))
                    rowItem.add(listOf("", "", ""))
                    rowItem.add(listOf("监装监卸", "中转信息", "备注"))
                    rowItem.add(listOf("", "", ""))
                    printCommonGridNew(rowItem)
                }

            }
        }
    }

    /**
     * 打印国际出港板箱过磅挂签（2列布局，支持合并单元格）
     */
    fun printGjcBoxWeighing(bean: GjcUldUseBean) {
        val rows = arrayListOf<GridRow>()

        // 第1行：日期 | 航班号
        rows.add(GridRow(
            left = CellData("日期:", "DATA:", bean.fdate),
            right = CellData("航班号:", "FLIGHT NO.:", bean.fno)
        ))

        // 第2行：目的站 | 板型
        rows.add(GridRow(
            left = CellData("目的站:", "DESTINATION:", bean.fdest),
            right = CellData("板型:", "PALLET TYPE:", bean.boardType)
        ))

        // 第3行：集装器编号（合并两列）
        rows.add(GridRow(
            merged = CellData("集装器编号:", "ULD NO.:", bean.uld)
        ))

        // 第4行：件数 | 重量（件数value暂不打印）
        rows.add(GridRow(
            left = CellData("件数:", "PIECES:", ""),
            right = CellData("重量:", "GROSS WEIGHT:", bean.totalWeight.toInt().toString())
        ))

        // 第5行：备注（合并两列）
        rows.add(GridRow(
            merged = CellData("备注:", "NOTES:", bean.remark)
        ))

        printMergedGrid(rows)
    }

    private fun printCommonGrid(rowItem: ArrayList<List<String>>) {
        val gridStartX = 80
        val gridStartY = 300
        val gridItemWidth = 170
        val gridItemHeight = 150
        val gridWidth = gridItemWidth * 6
        val gridHeight = gridItemHeight * 4

        val bytes = Tspl().apply {
            addSize(100, 100)
            addGap(3)
            addCls()
            // 标题居中（8个字 * 120像素/字 = 960像素宽，字体size=5）
//            val titleX = gridStartX + (gridWidth - 960) / 2
//            addText(titleX, 80, Tspl.FONT_TSS24, 0, 5, 5, "合肥新桥国际机场")

            addTextByBitmap(80, 80, 0, 130, "合肥新桥国际机场", Typeface.DEFAULT)

            // 表格横线
            for (i in 0 until 5) {
                addBar(gridStartX, gridStartY + (i * gridItemHeight), gridWidth, 2)
            }
            // 表格竖线
            for (i in 0 until 7) {
                addBar(gridStartX + (i * gridItemWidth), gridStartY, 2, gridHeight)
            }
            // 表格内容
            rowItem.forEachIndexed { index, list ->
                list.forEachIndexed { index2, str ->
                    addText(
                        gridStartX + (index2 * gridItemWidth) + 20,
                        gridStartY + (index * gridItemHeight) + 50,
                        Tspl.FONT_TSS24, 0, 1, 2, str
                    )
                }
            }
            addPrint(1)
        }.bytes
        portManager?.writeDataImmediately(bytes)
    }


    /**
     * 需求变更
     */
    private fun printCommonGridNew(rowItem: ArrayList<List<String>>) {
        //x
        val gridStartX = 30
        //y
        val gridStartY = 250
        //宽度
        val gridItemWidth = 375
        //高度
        val gridItemHeight = 110
        val gridWidth = gridItemWidth * 3
        val gridHeight = gridItemHeight * 8
        val bytes = Tspl().apply {
            addSize(100, 100)
            addGap(3)
            addCls()
            // 标题居中（8个字 * 120像素/字 = 960像素宽，字体size=5）
//            val titleX = gridStartX + (gridWidth - 960) / 2
//            addText(titleX, 80, Tspl.FONT_TSS24, 0, 5, 5, "合肥新桥国际机场")
            addTextByBitmap(80, 80, 0, 130, "合肥新桥国际机场", Typeface.DEFAULT)
            // 表格横线
            for (i in 0 until 9) {
                addBar(gridStartX, gridStartY + (i * gridItemHeight), gridWidth, 2)
            }
            // 表格竖线
            for (i in 0 until 4) {
                addBar(gridStartX + (i * gridItemWidth), gridStartY, 2, gridHeight)
            }
            // 表格内容
            rowItem.forEachIndexed { index, list ->
                list.forEachIndexed { index2, str ->
                    var padding = 0
                    var size = 3
                    if (index == 1 && index2 == 0) {
                        padding = -12
                    }
                    if (index % 2 == 0) {
                        padding = 15
                    }
                    if (str.length == 2) {
                        padding += 60
                    }
                    if (str.length == 3) {
                        padding += 30
                    }
                    if (str.length == 7) {
                        padding -= 30
                    }
                    addText(
                        gridStartX + (index2 * gridItemWidth) + 30 + padding,
                        gridStartY + (index * gridItemHeight) + 30,
                        Tspl.FONT_TSS24, 0, size, 2, str
                    )
                }
            }
            addPrint(1)
        }.bytes
        portManager?.writeDataImmediately(bytes)
    }

    /**
     * 打印支持合并单元格的表格
     */
    private fun printMergedGrid(rows: ArrayList<GridRow>) {
        val gridStartX = 30
        val titleTopMargin = 50      // 标题顶部间距
        val titleFontSize = 130      // 标题字体大小
        val titleTableGap = 40       // 标题与表格之间的间距
        val gridStartY = titleTopMargin + titleFontSize + titleTableGap  // 计算表格起始Y坐标
        val columnWidth = 570
        val rowHeight = 180          // 减小行高，适应较小字体
        val gridWidth = columnWidth * 2

        val bytes = Tspl().apply {
            addSize(100, 100)
            addGap(3)
            addCls()
            // 标题居中（8个字 * 120像素/字 = 960像素宽，字体size=5）
//            val titleX = gridStartX + (gridWidth - 960) / 2
//            addText(titleX, 60, Tspl.FONT_TSS24, 0, 5, 5, "合肥新桥国际机场")
            addTextByBitmap(80, titleTopMargin, 0, titleFontSize, "合肥新桥国际机场", Typeface.DEFAULT)

            // 绘制表格横线
            for (i in 0..rows.size) {
                addBar(gridStartX, gridStartY + (i * rowHeight), gridWidth, 2)
            }

            // 绘制表格竖线（需要根据是否合并单元格决定）
            rows.forEachIndexed { rowIndex, row ->
                val yTop = gridStartY + (rowIndex * rowHeight)

                // 左边线（总是绘制）
                addBar(gridStartX, yTop, 2, rowHeight)

                // 中间分隔线（非合并单元格才绘制）
                if (row.merged == null) {
                    addBar(gridStartX + columnWidth, yTop, 2, rowHeight)
                }

                // 右边线（总是绘制）
                addBar(gridStartX + gridWidth, yTop, 2, rowHeight)
            }

            // 填充单元格内容
            rows.forEachIndexed { rowIndex, row ->
                val yBase = gridStartY + (rowIndex * rowHeight)

                if (row.merged != null) {
                    // 合并单元格
                    renderCell(
                        cell = row.merged,
                        x = gridStartX + 20,
                        y = yBase,
                        cellWidth = gridWidth,
                        cellHeight = rowHeight,
                        isMerged = true
                    )
                } else {
                    // 左列单元格
                    row.left?.let { cell ->
                        renderCell(
                            cell = cell,
                            x = gridStartX + 20,
                            y = yBase,
                            cellWidth = columnWidth,
                            cellHeight = rowHeight
                        )
                    }
                    // 右列单元格
                    row.right?.let { cell ->
                        renderCell(
                            cell = cell,
                            x = gridStartX + columnWidth + 20,
                            y = yBase,
                            cellWidth = columnWidth,
                            cellHeight = rowHeight
                        )
                    }
                }
            }

            addPrint(1)
        }.bytes

        portManager?.writeDataImmediately(bytes)
    }

    /**
     * 渲染单元格内容
     * @param cell 单元格数据
     * @param x 起始X坐标
     * @param y 起始Y坐标
     * @param cellWidth 单元格宽度
     * @param cellHeight 单元格高度
     * @param isMerged 是否为合并单元格
     */
    private fun Tspl.renderCell(
        cell: CellData,
        x: Int,
        y: Int,
        cellWidth: Int,
        cellHeight: Int,
        isMerged: Boolean = false
    ) {
        // 字体大小配置
        val titleSize = 2       // 中文标签字体倍数
        val subtitleSize = 1    // 英文标签字体倍数
        val valueSize = 2       // 值字体倍数

        // Y坐标配置（基于24点阵字体，size=2约48像素高，size=1约24像素高）
        val titleY = y + 15                    // 中文标签Y位置
        val subtitleY = titleY + 70            // 英文标签Y位置（中文下方，间距加大）
        val valueY = y + (cellHeight / 2) - 24 // 值垂直居中

        // 中文标签
        addText(x, titleY, Tspl.FONT_TSS24, 0, titleSize, titleSize, cell.title)

        // 英文标签
        addText(x, subtitleY, Tspl.FONT_TSS24, 0, subtitleSize, subtitleSize, cell.subtitle)

        // 计算value的X坐标（根据英文标签长度动态调整）
        // 合并单元格（如集装器编号）使用更大的间距
        val extraGap = if (isMerged) 80 else 50
        val minOffset = if (isMerged) 280 else 220
        val labelWidth = cell.subtitle.length * 12 + extraGap
        val valueX = x + maxOf(labelWidth, minOffset)

        // 值（垂直居中）
        addText(valueX, valueY, Tspl.FONT_TSS24, 0, valueSize, valueSize, cell.value)
    }

    fun printTest() {
        getConnectedPrinters().forEach {
            val bytes = v(Instruction.TSC).bytes
            showLog("打印测试页 - ${it.printerDevice.printerName} \n${bytes.commonToUtf8String()}")
            it.print(bytes, null)
        }
    }

    fun test(car: String) {
        val tsc = LabelCommand()
        tsc.addSize(100, 100)
        tsc.addGap(3)
        tsc.addCls()
        tsc.addText(
            520,
            160,
            LabelCommand.FONTTYPE.SIMPLIFIED_24_CHINESE,
            LabelCommand.ROTATION.ROTATION_0,
            LabelCommand.FONTMUL.MUL_5,
            LabelCommand.FONTMUL.MUL_5,
            car
        )
        tsc.addQRCode(320, 360, LabelCommand.EEC.LEVEL_H, 25, LabelCommand.ROTATION.ROTATION_0, car)
        tsc.addPrint(1)
        val bytes = tsc.command.toByteArray()

        portManager?.writeDataImmediately(bytes)
    }

    /**
     * 释放连接
     */
    fun release() {
        getConnectedPrinters().forEach {
            it.disconnect()
        }
    }

    /**
     * 获取连接的设备
     */
    private fun getConnectedPrinters(): List<Printer> =
        Printer.getConnectedPrinters() ?: emptyList()

    private fun showLog(message: String) {
        loge("PrinterUtils : $message")
    }

}