package com.example.ops_android.printer

import android.content.Context
import android.graphics.Bitmap
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.bld.PrintManager
import android.bld.print.aidl.PrinterBinderListener
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout

class PrinterManager(private val context: Context) {

    // ── 内部状态 ────────────────────────────────────────────
    internal var printManager: PrintManager? = null
        private set
    @Volatile internal var isOpen = false
        private set
    @Volatile private var intentionalClose = false
    private var connectionCallback: ((Boolean, String) -> Unit)? = null
    private val mainHandler = Handler(Looper.getMainLooper())

    companion object {
        private const val TAG = "PrinterManager"
        private const val CONNECT_TIMEOUT_MS = 10_000L

        // 错误码
        internal const val ERROR_NO_ERROR = 0
        internal const val ERROR_DEV_IS_BUSY = 1
        internal const val ERROR_PRINT_HOT = 2
        internal const val ERROR_PRINT_NOPAPER = 3
        internal const val ERROR_DEV_NO_BATTERY = 4
        internal const val ERROR_DEV_FEED = 5
        internal const val ERROR_DEV_PRINT = 6
        internal const val ERROR_DEV_BMARK = 7
        internal const val ERROR_DEV_NOT_OPEN = 16
        internal const val ERROR_NO_DATA = 17
        internal const val ERROR_DATA_INVALID = 18
        internal const val ERROR_CMD = 19
        internal const val ERROR_GRAY_INVALID = 20

        fun getErrorMessage(errorCode: Int): String = when (errorCode) {
            ERROR_NO_ERROR -> "正常"
            ERROR_DEV_IS_BUSY -> "设备忙"
            ERROR_PRINT_HOT -> "打印头过热"
            ERROR_PRINT_NOPAPER -> "缺纸"
            ERROR_DEV_NO_BATTERY -> "电量不足"
            ERROR_DEV_FEED -> "走纸错误"
            ERROR_DEV_PRINT -> "打印错误"
            ERROR_DEV_BMARK -> "黑标错误"
            ERROR_DEV_NOT_OPEN -> "设备未打开"
            ERROR_NO_DATA -> "无数据"
            ERROR_DATA_INVALID -> "数据无效"
            ERROR_CMD -> "指令错误"
            ERROR_GRAY_INVALID -> "浓度无效"
            165 -> "数据输入错误"
            else -> "未知错误($errorCode)"
        }
    }

    // ── 连接回调 ───（运行在 Binder 线程，需切换到主线程）──────
    private val printerListener = object : PrinterBinderListener {
        override fun onPrintCallback(status: Int) {
            Log.d(TAG, "Printer callback: status=$status (${getErrorMessage(status)})")
            mainHandler.post {
                when (status) {
                    ERROR_NO_ERROR -> {
                        isOpen = true
                        connectionCallback?.invoke(true, "打印机已就绪")
                    }
                    ERROR_DEV_NOT_OPEN -> {
                        if (intentionalClose) return@post
                        isOpen = false
                        connectionCallback?.invoke(false, "设备未打开，请重新连接")
                    }
                    else -> connectionCallback?.invoke(false, getErrorMessage(status))
                }
            }
        }
    }

    fun setConnectionCallback(callback: (Boolean, String) -> Unit) {
        connectionCallback = callback
    }

    // ══════════════════════════════════════════════════════════
    //  连接管理
    // ══════════════════════════════════════════════════════════

    fun bindService() {
        notifyConnection(false, "正在连接打印服务...")
        Thread {
            try {
                kotlinx.coroutines.runBlocking {
                    withTimeout(CONNECT_TIMEOUT_MS) {
                        withContext(Dispatchers.IO) {
                            intentionalClose = false
                            Log.d(TAG, "Attempting to get PrintManager instance...")
                            val manager = PrintManager.getDefaultInstance(context)
                            if (manager == null) {
                                notifyConnection(false, "设备不支持打印功能")
                                return@withContext
                            }
                            printManager = manager
                            manager.addPrintListener(printerListener)
                            Log.d(TAG, "Opening printer...")
                            val success = manager.open()
                            Log.d(TAG, "open() returned: $success")
                            if (success) {
                                isOpen = true
                                val version = manager.getPrinterVer()
                                if (version != null) {
                                    notifyConnection(true, "打印机已连接 (固件: $version)")
                                } else {
                                    notifyConnection(true, "打印机已连接")
                                }
                            } else {
                                isOpen = false
                                notifyConnection(false, "打印机打开失败，请检查设备")
                            }
                        }
                    }
                }
            } catch (e: TimeoutCancellationException) {
                Log.e(TAG, "bindService timeout after ${CONNECT_TIMEOUT_MS}ms")
                notifyConnection(false, "连接超时，请检查打印服务是否运行")
            } catch (e: Exception) {
                Log.e(TAG, "Failed to open print service", e)
                notifyConnection(false, "连接异常: ${e.message}")
            }
        }.start()
    }

    fun unbindService() {
        Thread {
            try {
                if (isOpen) {
                    printManager?.removePrintListener(printerListener)
                    printManager?.close()
                    isOpen = false
                    notifyConnection(false, "服务已断开")
                }
            } catch (e: Exception) {
                Log.e(TAG, "Failed to close print service", e)
            }
        }.start()
    }

    fun isConnected(): Boolean = isOpen && printManager != null

    fun getFirmwareVersion(): String? {
        return try {
            printManager?.getPrinterVer()
        } catch (e: Exception) {
            Log.e(TAG, "Failed to get printer version", e)
            null
        }
    }

    // ══════════════════════════════════════════════════════════
    //  设备控制
    // ══════════════════════════════════════════════════════════

    fun ensureOpen(): Result<Unit> = runCatching {
        checkPrinter()
        if (!isOpen) {
            intentionalClose = false
            val opened = printManager?.open() ?: false
            if (!opened) throw Exception("设备未打开，请重新绑定服务")
            isOpen = true
        }
    }

    fun initDevice(): Result<Unit> = runCatching {
        ensureOpen().getOrThrow()
        val result = printManager!!.reset()
        if (result != ERROR_NO_ERROR) throw Exception("初始化失败: ${getErrorMessage(result)}")
    }

    fun closeDevice(): Result<Unit> = runCatching {
        checkOpen()
        isOpen = false
        intentionalClose = true
        printManager?.close()
    }

    fun commit(): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.start()
    }

    // ══════════════════════════════════════════════════════════
    //  内容添加（供 PrintJob 使用）
    // ══════════════════════════════════════════════════════════

    internal fun addText(text: String): Result<Unit> = runCatching {
        checkOpen()
        val pm = printManager!!
        pm.addText(0, pm.getFontSize() ?: 24, pm.isFontBold() ?: false, pm.isUnderLine() ?: false, text)
    }

    internal fun addQR(content: String): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.addQRCode(2, 384, content)
    }

    internal fun addBarcode(content: String): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.addBarcode(2, 60, content, 73, 3)
    }

    internal fun addLineFeed(count: Int = 1): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.addLineFeed(count)
    }

    // ══════════════════════════════════════════════════════════
    //  样式设置
    // ══════════════════════════════════════════════════════════

    fun setFontSize(size: Int): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.setFontSize(size)
    }

    fun setBold(bold: Boolean): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.setFontBold(bold)
    }

    fun setUnderline(underline: Boolean): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.setUnderLine(underline)
    }

    fun setDensity(level: Int): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.setDensity(level)
    }

    // ══════════════════════════════════════════════════════════
    //  走纸控制
    // ══════════════════════════════════════════════════════════

    fun setPaperGap(dots: Int): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.setFeedPaperSpace(dots)
    }

    fun setUnwindLength(len: Int): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.setUnwindPaperLen(len)
    }

    fun getUnwindPaperLenInt(): Int? = try {
        printManager?.unwindPaperLen ?: printManager?.getUnwindPaperLen()
    } catch (e: Exception) {
        Log.e(TAG, "getUnwindPaperLen failed", e)
        null
    }

    fun getFeedPaperSpaceInt(): Int? = try {
        printManager?.feedPaperSpace ?: printManager?.getFeedPaperSpace()
    } catch (e: Exception) {
        Log.e(TAG, "getFeedPaperSpace failed", e)
        null
    }

    // ══════════════════════════════════════════════════════════
    //  黑标 / 标签
    // ══════════════════════════════════════════════════════════

    fun enableMarkDetection(enable: Boolean): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.setBlackLabel(enable)
    }

    fun gotoNextMark(): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.addLineFeed(1)
        printManager!!.start()
    }

    // ══════════════════════════════════════════════════════════
    //  图片
    // ══════════════════════════════════════════════════════════

    fun printImage(bitmap: Bitmap, align: Int = 1): Result<Unit> = runCatching {
        checkOpen()
        printManager!!.addImage(align, bitmap)
    }

    // ══════════════════════════════════════════════════════════
    //  便捷方法
    // ══════════════════════════════════════════════════════════

    fun quickText(text: String): Result<Unit> = runCatching {
        initDevice().getOrThrow()
        addText(text).getOrThrow()
        commit().getOrThrow()
    }

    fun quickLabel(text: String): Result<Unit> = runCatching {
        initDevice().getOrThrow()
        enableMarkDetection(true).getOrThrow()
        addText(text).getOrThrow()
        commit().getOrThrow()
    }

    /** 创建链式打印任务 */
    fun buildJob(): PrintJob = PrintJob(this)

    // ── 内部工具 ────────────────────────────────────────────

    internal fun checkPrinter() {
        if (printManager == null)
            throw Exception("打印服务未初始化，请先点击'绑定服务'")
    }

    private fun checkOpen() {
        checkPrinter()
        if (!isOpen)
            throw Exception("打印服务未连接，请先点击'绑定服务'")
    }

    private fun notifyConnection(connected: Boolean, message: String) {
        mainHandler.post { connectionCallback?.invoke(connected, message) }
    }
}
