package com.grkj.iscs

import android.bluetooth.BluetoothGatt
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData
import com.clj.fastble.BleManager
import com.clj.fastble.data.BleDevice
import com.clj.fastble.exception.BleException
import com.google.gson.Gson
import com.grkj.iscs.ble.BleBean
import com.grkj.iscs.ble.BleCmdManager
import com.grkj.iscs.ble.BleConst
import com.grkj.iscs.ble.BleConst.STATUS_READY
import com.grkj.iscs.ble.BleConst.STATUS_WORK
import com.grkj.iscs.ble.BleUtil
import com.grkj.iscs.ble.CustomBleGattCallback
import com.grkj.iscs.ble.CustomBleIndicateCallback
import com.grkj.iscs.ble.CustomBleScanCallback
import com.grkj.iscs.ble.CustomBleWriteCallback
import com.grkj.iscs.extentions.removeLeadingZeros
import com.grkj.iscs.extentions.serialNo
import com.grkj.iscs.extentions.startsWith
import com.grkj.iscs.extentions.toHexStrings
import com.grkj.iscs.modbus.DockBean
import com.grkj.iscs.modbus.ModBusController
import com.grkj.iscs.model.Constants.PERMISSION_REQUEST_CODE
import com.grkj.iscs.model.Constants.USER_TYPE_LOCKER
import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_CARD
import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_FINGERPRINT
import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_KEY
import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_LOCK
import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD
import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_KEY
import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_LOCK
import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_PORTABLE
import com.grkj.iscs.model.bo.DeviceTakeUpdateBO
import com.grkj.iscs.model.bo.WorkTicketGetBO
import com.grkj.iscs.model.bo.WorkTicketSendBO
import com.grkj.iscs.model.bo.WorkTicketSendBO.LockListBO
import com.grkj.iscs.model.eventmsg.CurrentModeMsg
import com.grkj.iscs.model.eventmsg.DeviceTakeUpdateMsg
import com.grkj.iscs.model.eventmsg.LoadingMsg
import com.grkj.iscs.model.eventmsg.MsgEvent
import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_CURRENT_MODE
import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_DEVICE_TAKE_UPDATE
import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_LOADING
import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_SWITCH_MODE
import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_UPDATE_TICKET_PROGRESS
import com.grkj.iscs.model.eventmsg.SwitchModeMsg
import com.grkj.iscs.model.eventmsg.UpdateTicketProgressMsg
import com.grkj.iscs.model.vo.lock.LockTakeUpdateReqVO
import com.grkj.iscs.model.vo.ticket.LockPointUpdateReqVO
import com.grkj.iscs.model.vo.ticket.TicketDetailRespVO
import com.grkj.iscs.util.ActivityUtils
import com.grkj.iscs.util.CommonUtils
import com.grkj.iscs.util.Executor
import com.grkj.iscs.util.NetApi
import com.grkj.iscs.util.SPUtils
import com.grkj.iscs.util.ToastUtils
import com.grkj.iscs.util.log.LogUtil
import com.grkj.iscs.view.base.BaseActivity
import com.grkj.iscs.view.dialog.TipDialog
import pub.devrel.easypermissions.AfterPermissionGranted

/**
 * 业务层管理
 */
object BusinessManager {
    // 消息总线
    val mEventBus = MutableLiveData<MsgEvent>()

    // 已连接的蓝牙钥匙集合
    var deviceList: MutableList<BleBean> = mutableListOf()
    // 是否正在进行准备流程
    private var isPreparing: Boolean = false

    // Modbus数据页面监听
    class DeviceListener(
        val key: Any,
        val callBack: (DockBean) -> Unit
    )
    private val listeners = ArrayList<DeviceListener>()

    // 蓝牙连接准备监听
    data class ConnectListener(
        val mac: String,
        val callBack: ((Boolean, BleBean?) -> Unit)? = null
    )
    // 蓝牙连接准备监听集合，全是待准备连接的，准备完毕的会移除
    private val connectListeners = mutableListOf<ConnectListener>()

    // 归还设备是否需要登录
    var NEED_AUTH = true

    // 归还设备是否需要登录及角色验证
    private var CAN_RETURN = true
        get() {
            val loginUser = SPUtils.getLoginUser(MyApplication.instance!!.applicationContext!!)
            return (NEED_AUTH && loginUser != null) || !NEED_AUTH
        }

    // 设备待取列表(需要报给后台的列表，等实际取完再上报)
    val mDeviceTakeList = mutableListOf<DeviceTakeUpdateBO>()

    // 是否是测试人员登录的
    var isTestMode = false

    /**
     * 初始化消息总线
     */
    fun initMsgEventBus() {
        mEventBus.observeForever {
            LogUtil.i("msgEvent : $it")
            when (it.code) {
                // loading消息
                MSG_EVENT_LOADING -> {
                    Executor.runOnMain {
                        val loadingMsg = it.data as LoadingMsg
                        (ActivityUtils.currentActivity() as BaseActivity<*>).handleLoading(loadingMsg.isShow, loadingMsg.loadingText)
                    }
                }
                // 设备取出
                MSG_EVENT_DEVICE_TAKE_UPDATE -> {
                    handleDeviceTake(it.data as DeviceTakeUpdateMsg)
                }
                // 钥匙当前模式
                MSG_EVENT_CURRENT_MODE -> {
                    handleCurrentMode(it.data as CurrentModeMsg)
                }
                // 钥匙切换模式结果
                MSG_EVENT_SWITCH_MODE -> {
                    when ((it.data as SwitchModeMsg).job) {
                        // 工作模式
                        1 -> {
                            if (it.data.res == 1) {
                                // 只能在这里断开，不能全部断开
                                BleManager.getInstance().disconnect(it.data.bleBean.bleDevice)

                                // 打开钥匙卡扣
                                val keyBean = ModBusController.getKeyByMac(it.data.bleBean.bleDevice.mac)
                                if (keyBean == null) {
                                    mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "未找到钥匙信息", false)))
                                    ToastUtils.tip(R.string.key_not_exists)
                                } else {
                                    mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, true)))
                                    val dock = ModBusController.getDockByKeyMac(it.data.bleBean.bleDevice.mac)
                                    ModBusController.controlKeyBuckle(true, keyBean.isLeft, dock?.addr)
                                }
                                // 强制结束Loading防止有loading仍在显示
                                Executor.delayOnMain(500) {
                                    mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, true)))
                                }
                            } else {
                                LogUtil.e("切换工作模式失败 : ${it.data.bleBean.bleDevice.mac}")
                                Executor.delayOnMain(500) {
                                    switchWorkMode(it.data.bleBean.bleDevice, false)
                                }
                            }
                        }
                        // 待机模式
                        2 -> {
                            if (it.data.res == 1) {
                                // 延时再次获取当前状态，触发handleCurrentMode里工作票下发状态检查
                                Executor.delayOnMain(500) {
                                    getCurrentStatus(1, it.data.bleBean.bleDevice)
                                }
                            } else {
                                LogUtil.e("切换待机模式失败 : ${it.data.bleBean.bleDevice.mac}")
                                Executor.delayOnMain(500) {
                                    switchReadyMode(it.data.bleBean.bleDevice)
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /****************************************** ModBus ******************************************/

    fun connectDock(isNeedInit: Boolean = false) {
        // 不再使用SlaveCount，改用地址池
//        ModBusController.setSlaveCount(100)
        ModBusController.interruptReadTrashBinStatus(false)
        ModBusController.start(MyApplication.instance!!.applicationContext)
        ModBusController.unregisterListener(MyApplication.instance!!.applicationContext)

        if (isNeedInit) {
            ModBusController.initDevicesStatus()
        }
    }

    fun disconnectDock() {
        ModBusController.stop()
    }

    fun registerStatusListener(key: Any, listener: (DockBean) -> Unit) {
        listeners.add(DeviceListener(key, listener))
    }

    fun unregisterListener(key: Any) {
        val it = listeners.iterator()
        while (it.hasNext()) {
            if (it.next().key == key) {
                it.remove()
            }
        }
    }

    /**
     * 总的监听，做预处理，其余的所有监听均使用本监听处理后的数据，只允许调用一次
     */
    fun registerMainListener() {
        ModBusController.registerStatusListener(this) { res ->
            LogUtil.i("设备状态：${(res as List<ByteArray>).map { it.toHexStrings() }}")
            if (res.isEmpty() || res.any { it.isEmpty() }) {
                var tipStr = MyApplication.instance?.applicationContext?.getString(R.string.no_response_board_exists) + " : "
                val addressList = mutableListOf<String>()

                ModBusController.modBusManager?.mSlaveAddressList?.forEach { itDock ->
                    if (res.none { it.isNotEmpty() && it[0] == itDock }) {
                        addressList.add("0x${String.format("%02X", itDock)}")
                    }
                }
                tipStr += addressList
                ToastUtils.tip(tipStr)
            }
            res.forEach { bytes ->
                val dockBean = ModBusController.updateStatus(bytes) ?: return@forEach
                ModBusController.isInitReady = true
                if (!CAN_RETURN) {
                    return@forEach
                }
                when (dockBean.type) {
                    DOCK_TYPE_KEY -> {
                        dockBean.getKeyList().forEach { keyBean ->
                            if (keyBean.isExist) {
                                // 放回钥匙，读取rfid
                                ModBusController.readKeyRfid(dockBean.addr, if (keyBean.isLeft) 0 else 1) { isLeft, res ->
                                    if (res.size < 11) {
                                        LogUtil.e("Key rfid error")
                                        return@readKeyRfid
                                    }
                                    val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
                                    ModBusController.updateKeyRfid(dockBean.addr, keyBean.isLeft, rfid)
                                    NetApi.getKeyInfo(rfid) {
                                        if (it != null && !it.macAddress.isNullOrEmpty()) {
                                            ModBusController.updateKeyMac(dockBean.addr, keyBean.isLeft, it.macAddress)
                                            // TODO 移动到HomePresenter里，根据业务进行处理
//                                            showKeyReturnDialog(it.macAddress, isLeft, dockBean.addr.toInt())
//                                            registerConnectListener(it.macAddress)
                                        } else {
                                            LogUtil.e("Get key info fail : $rfid")
                                            ToastUtils.tip(R.string.get_key_info_fail)
                                        }
                                    }
                                    // TODO 蓝牙通信
                                }
//                                ModBusController.controlKeyBuckle(false, isLeft = true, dockBean.addr.toInt() - 1)
                            } else {
                                // 移出待连监听集合，防止connectKey循环失败
                                keyBean.mac?.let {
                                    unregisterConnectListener(it)
                                }
                                mEventBus.postValue(MsgEvent(MSG_EVENT_DEVICE_TAKE_UPDATE, DeviceTakeUpdateMsg(DEVICE_TYPE_KEY, keyBean.rfid)))
                            }
                        }
                    }
                    DOCK_TYPE_LOCK -> {
                        dockBean.getLockList().forEach { lockBean ->
                            if (lockBean.isExist) {
                                ModBusController.readLockRfid(dockBean.addr, lockBean.idx) { res ->
                                    if (res.size < 11) {
                                        LogUtil.e("Lock rfid error")
                                        return@readLockRfid
                                    }
                                    val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
                                    ModBusController.updateLockRfid(dockBean.addr, lockBean.idx, rfid)
                                    NetApi.getLockInfo(rfid) {
                                        if (it != null) {
                                            // TODO 考虑快速拿取
                                            ModBusController.controlLockBuckle(false, dockBean.addr, lockBean.idx) { itRst ->
                                                if (itRst.isNotEmpty()) {
                                                    // 上报锁具信息
                                                    NetApi.updateLockReturn(rfid, MyApplication.instance!!.serialNo()) {}
                                                }
                                            }
                                        }
                                    }
                                }
                            } else {
                                mEventBus.postValue(MsgEvent(MSG_EVENT_DEVICE_TAKE_UPDATE, DeviceTakeUpdateMsg(DEVICE_TYPE_LOCK, lockBean.rfid)))
                            }
                        }
                    }
                    DOCK_TYPE_ELEC_LOCK_BOARD -> {
                        // TODO 占位
                    }
                    DOCK_TYPE_PORTABLE -> {
                        // TODO 便携式待完善
                        dockBean.deviceList.forEach { deviceBean ->
                            if (deviceBean.isExist) {
                                when (deviceBean.type) {
                                    DEVICE_TYPE_KEY -> {
                                        ModBusController.readKeyRfid(dockBean.addr, deviceBean.idx) { isLeft, res ->
                                            if (res.size < 11) {
                                                LogUtil.e("Key rfid error")
                                                return@readKeyRfid
                                            }
                                            val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
                                            ModBusController.updateKeyRfid(dockBean.addr, true, rfid)
                                            NetApi.getKeyInfo(rfid) {
                                                if (it != null && !it.macAddress.isNullOrEmpty()) {
                                                    ModBusController.updateKeyMac(dockBean.addr, isLeft, it.macAddress)
//                                                    showKeyReturnDialog(it.macAddress, isLeft, dockBean.addr)
                                                } else {
                                                    ToastUtils.tip(R.string.get_key_info_fail)
                                                }
                                            }
                                            // TODO 蓝牙通信
                                        }
//                                        ModBusController.controlKeyBuckle(false, isLeft = true, dockBean.addr.toInt() - 1)
                                    }
                                    DEVICE_TYPE_LOCK -> {
                                        ModBusController.readLockRfid(dockBean.addr, deviceBean.idx) { res ->
                                            if (res.size < 11) {
                                                LogUtil.e("Lock rfid error")
                                                return@readLockRfid
                                            }
                                            val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
                                            ModBusController.updateLockRfid(dockBean.addr, deviceBean.idx, rfid)

                                            NetApi.getLockInfo(rfid) {
                                                if (it != null) {
                                                    // TODO 考虑快速拿取
                                                    ModBusController.controlLockBuckle(false, dockBean.addr, deviceBean.idx) { itRst ->
                                                        if (itRst.isNotEmpty()) {
                                                            // 上报锁具信息
                                                            NetApi.updateLockReturn(rfid, MyApplication.instance!!.serialNo()) {}
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    DEVICE_TYPE_CARD -> {
                                        ModBusController.readPortalCaseCardRfid(dockBean.addr) { res ->
                                            if (res.size < 11) {
                                                LogUtil.e("Portal Case card rfid error")
                                                return@readPortalCaseCardRfid
                                            }
                                            val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
                                            LogUtil.i("卡片RFID ： $rfid")
                                        }
                                    }
                                    DEVICE_TYPE_FINGERPRINT -> {

                                    }
                                }
                            }
                        }
                    }
                }
                Executor.delayOnMain(200) {
                    listeners.forEach { it.callBack(dockBean) }
                }
            }
        }
    }

    /**
     * 钥匙归还提示确认弹框
     */
    private fun showKeyReturnDialog(onConfirm: () -> Unit, onCancel: () -> Unit) {
        val ctx = ActivityUtils.currentActivity() as BaseActivity<*>
        val dlg = TipDialog(ctx)
        dlg.setTip(ctx.getString(R.string.key_return_tip))
        dlg.setConfirmListener {
            onConfirm.invoke()
        }
        dlg.setCancelListener {
            onCancel.invoke()
        }
        dlg.show()
    }

    fun readLockBuckleStatus() {
        // TODO slaveIdx暂时写死，调试用
        ModBusController.readBuckleStatus(true, 0) { type, res ->
            LogUtil.i("单slave卡扣状态 ： $type - ${res.toHexStrings()}")
            when (type) {
                0 -> {
                    val isLeftLock = (res[4].toInt() shr 0) and 0x1 == 1
                    val isRightLock = (res[4].toInt() shr 4) and 0x1 == 1
                    LogUtil.i("锁具底座卡扣状态 ： $isLeftLock - $isRightLock")
                }
                1 -> {
                    val tempList = mutableListOf<Boolean>()
                    for (i in 0..7) {
                        tempList.add((res[4].toInt() shr i) and 0x1 == 1)
                    }
                    LogUtil.i("锁具底座卡扣1-8状态 ： $tempList")
                }
                2 -> {
                    val lock9Status = (res[4].toInt() shr 0) and 0x1 == 1
                    val lock10Status = (res[4].toInt() shr 1) and 0x1 == 1
                    LogUtil.i("锁具底座卡扣9、10状态 ： $lock9Status - $lock10Status")
                }
            }
        }
    }

    fun readKeyBuckleStatus() {
        // TODO slaveIdx暂时写死，调试用
        ModBusController.readBuckleStatus(false, 1) { type, res ->
            LogUtil.i("单slave卡扣状态 ： $type - ${res.toHexStrings()}")
            // TODO 待验证
            when (type) {
                0 -> {
                    val isLeftLock = (res[4].toInt() shr 0) and 0x1 == 1
                    val isRightLock = (res[4].toInt() shr 4) and 0x1 == 1
                    LogUtil.i("钥匙底座卡扣状态 ： $isLeftLock - $isRightLock")
                }
                1 -> {
                    val tempList = mutableListOf<Boolean>()
                    for (i in 0..7) {
                        tempList.add((res[4].toInt() shr i) and 0x1 == 1)
                    }
                    LogUtil.i("锁具底座卡扣1-8状态 ： $tempList")
                }
                2 -> {
                    val lock9Status = (res[4].toInt() shr 0) and 0x1 == 1
                    val lock10Status = (res[4].toInt() shr 1) and 0x1 == 1
                    LogUtil.i("锁具底座卡扣9、10状态 ： $lock9Status - $lock10Status")
                }
            }
        }
    }

    /**
     * 检查钥匙和锁具数量
     *
     * @param needLockCount 需要的锁具的数量（可能在别的机柜取过）
     * @param isNeedKey 是否需要钥匙（可能存在前一次拿了部分锁和钥匙，有锁取出失败）
     */
    fun checkEquipCount(needLockCount: Int, isNeedKey: Boolean, callBack: (Pair<Byte, DockBean.KeyBean?>?, MutableMap<Byte, MutableList<DockBean.LockBean>>) -> Unit) {
        var lockCount = 0
        val lockMap = ModBusController.getLocks(needLockCount)
        LogUtil.i("checkEquipCount : $lockMap")
        lockMap.forEach { (_, rfidList) ->
            lockCount += rfidList.size
        }

        var tipStr = ""
        if (lockCount < needLockCount) {
            val msg = MyApplication.instance!!.applicationContext.resources.getString(R.string.lock_is_not_enough)
            LogUtil.w(msg)
            tipStr = msg
        }

        var key: Pair<Byte, DockBean.KeyBean?>? = null
        if (isNeedKey && lockCount >= needLockCount) {
            key = ModBusController.getOneKey()
            if (key == null) {
                val msg = MyApplication.instance!!.applicationContext.resources.getString(R.string.key_is_not_enough)
                LogUtil.w(msg)
                tipStr = if (tipStr.isEmpty()) {
                    msg
                } else {
                    tipStr + "\n" + msg
                }
            }
        }

        if (tipStr.isNotEmpty()) {
            ToastUtils.tip(tipStr)
        }
        callBack.invoke(key, lockMap)
    }


    /****************************************** 蓝牙 ******************************************/
    /******************************************蓝牙通用准备******************************************/

    /**
     * 注册连接监听
     */
    fun registerConnectListener(mac: String, callBack: ((Boolean, BleBean?) -> Unit)? = null) {
        LogUtil.i("registerConnectListener : $mac")
        if (connectListeners.any { it.mac == mac }) {
            LogUtil.w("Ignore mac : $mac 已存在")
            return
        }
        if (deviceList.none { it.bleDevice.mac == mac }) {
            connectListeners.add(ConnectListener(mac, callBack))
            if (connectListeners.size > 0) {
                Executor.runOnMain {
                    connectKey()
                }
            }
        } else {
            val bean = deviceList.find { it.bleDevice.mac == mac }
            if (bean?.token == null) {
                connectListeners.add(ConnectListener(mac, callBack))
                if (connectListeners.size > 0) {
                    Executor.runOnMain {
                        connectKey()
                    }
                }
                return
            }
            callBack?.invoke(true, bean)
        }
    }

    /**
     * 连接监听反注册
     */
    fun unregisterConnectListener(mac: String, bleBean: BleBean? = null) {
        LogUtil.i("unregisterConnectListener : $mac")
        connectListeners.find { it.mac == mac }?.let {
            // TODO 移除的时候是否要回调待定
//            it.callBack?.invoke(true, bleBean)
            connectListeners.remove(it)
        }
    }

    /**
     * 连接钥匙，单个mac走完prepare再进行下一个
     */
    private fun connectKey() {
        if (connectListeners.isEmpty()) {
            return
        }
        if (isPreparing) {
            Executor.delayOnMain(1000) {
                connectKey()
            }
            return
        }
        isPreparing = true
        val listener = connectListeners[0]
        prepareBle(listener.mac, ActivityUtils.currentActivity() as BaseActivity<*>, false) { isDone, bleBean ->
            Executor.runOnMain {
                isPreparing = false
                if (!isDone) {
                    // 判断是否仍然待连，防止拿走；移到末尾，防止循环影响
                    unregisterConnectListener(listener.mac)
                    Executor.delayOnMain(2000) {
                        registerConnectListener(listener.mac, listener.callBack)
                    }
                    return@runOnMain
                }
                // 判断是否仍然待连，防止拿走
                // TODO 暂时只处理准备成功
                if (connectListeners.contains(listener)) {
                    listener.callBack?.invoke(true, bleBean)
                    unregisterConnectListener(listener.mac)
                }
                if (connectListeners.isNotEmpty()) {
                    connectKey()
                }
            }
        }
    }

    /**
     * @param loadingCallBack 是否显示loading、loading文字、流程是否结束
     * @param prepareDoneCallBack 蓝牙连接是否成功、蓝牙连接对象
     */
    private fun prepareBle(
        mac: String,
        activity: AppCompatActivity,
        isNeedLoading: Boolean = false,
        prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
    ) {
        Executor.runOnMain {
            // 如果是已经连上的设备，从indicate开始往下走，不需要再扫描了
//            if (BleManager.getInstance().isConnected(mac)) {
//                deviceList.find { it.bleDevice.mac == mac }?.let { itBleDevice ->
//                    indicate(itBleDevice, isNeedLoading, prepareDoneCallBack)
//                    return@runOnMain
//                }
//            }
            CommonUtils.checkBlePermission(activity) {
                doScanBle(mac, isNeedLoading, prepareDoneCallBack)
            }
        }
    }

    @AfterPermissionGranted(PERMISSION_REQUEST_CODE)
    private fun doScanBle(mac: String, isNeedLoading: Boolean = false, prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?) {
        LogUtil.i("doScanBle：$mac")
        if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(true, "正在扫描设备...", null)))
        BleUtil.instance?.scan(object : CustomBleScanCallback() {
            override fun onPrompt(promptStr: String?) {
                // 蓝牙未启动重试
                BleManager.getInstance().enableBluetooth()
                doScanBle(mac, isNeedLoading, prepareDoneCallBack)
            }

            override fun onScanStarted(success: Boolean) {
                LogUtil.i("onScanStarted：${success}")
                if (!success) {
                    if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, null)))
                    prepareDoneCallBack?.invoke(false, null)
                }
            }

            override fun onScanning(bleDevice: BleDevice?) {
                LogUtil.i("onScanning：${bleDevice?.mac}")
                bleDevice?.let {
                    if (connectListeners.any { itData -> itData.mac == bleDevice.mac }) {
                        doConnect(it, isNeedLoading, prepareDoneCallBack)
                    }
                }
            }

            override fun onScanFinished(scanResultList: MutableList<BleDevice>?) {
                LogUtil.i("onScanFinished: $mac")
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, null)))
                if (connectListeners.any { it.mac == mac }) {
                    LogUtil.w("$mac is not scanned")
                    prepareDoneCallBack?.invoke(false, null)
                }
            }
        })
    }

    /**
     * 连接蓝牙设备
     */
    private fun doConnect(
        bleDevice: BleDevice,
        isNeedLoading: Boolean = false,
        prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
    ) {
        if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(true, CommonUtils.getStr(R.string.ble_connecting), null)))
        BleManager.getInstance().disconnect(bleDevice)
        BleUtil.instance?.connectBySelect(bleDevice,
            object : CustomBleGattCallback() {
                override fun onPrompt(promptStr: String?) {
                    if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, promptStr, null)))
                }

                override fun onStartConnect() {}

                override fun onConnectFail(bleDevice: BleDevice?, exception: BleException?) {
                    if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, CommonUtils.getStr(R.string.ble_connect_fail), false)))
                    LogUtil.e("onConnectFail : $bleDevice - ${exception?.description}")
                    prepareDoneCallBack?.invoke(false, null)
                }

                override fun onConnectSuccess(bleDevice: BleDevice?, gatt: BluetoothGatt?, status: Int) {
                    if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, null)))
                    LogUtil.i("onConnectSuccess : ${bleDevice?.mac}")
                    bleDevice?.let {
                        deviceList.removeIf { it.bleDevice.mac == bleDevice.mac }
                        val bleBean = BleBean(it)
                        deviceList.add(bleBean)
                        // 设置MTU
                        Executor.delayOnMain(200) {
                            BleUtil.instance?.setMtu(it)
                        }
                        // 监听
                        Executor.delayOnMain(500) {
                            indicate(bleBean, isNeedLoading, prepareDoneCallBack)
                        }
                    }
                }

                override fun onDisConnected(isActiveDisConnected: Boolean, device: BleDevice?, gatt: BluetoothGatt?, status: Int) {
                    if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, false)))
                    LogUtil.i("onDisConnected : ${device?.mac} - $isActiveDisConnected")
                    getBleDeviceByMac(device?.mac)?.let {
                        deviceList.remove(it)
                    }
                    bleDevice.mac?.let { itMac ->
                        unregisterConnectListener(itMac)
                    }
                    if (!isActiveDisConnected) {
                        // 测试模式下不重连
                        if (isTestMode) {
                            return
                        }
                        // 断开和重连之间最好间隔一段时间，否则可能会出现长时间连接不上的情况
                        Executor.delayOnMain(300) {
                            registerConnectListener(bleDevice.mac)
                        }
                    }
                }
            })
    }

    /**
     * 监听蓝牙设备
     */
    private fun indicate(
        bleBean: BleBean?,
        isNeedLoading: Boolean = false,
        prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
    ) {
        if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(true, "开始监听...", null)))
        bleBean?.let {
            BleUtil.instance?.indicate(it.bleDevice, indicateCallback = object : CustomBleIndicateCallback() {
                override fun onPrompt(promptStr: String?) {
                    LogUtil.i("indicate onPrompt ： $promptStr")
                }

                override fun onConnectPrompt(promptStr: String?) {
                    LogUtil.i("indicate onConnectPrompt ： $promptStr")
                }

                override fun onDisConnectPrompt(promptStr: String?) {
                    LogUtil.i("indicate onDisConnectPrompt ： $promptStr")
                }

                override fun onIndicateSuccess() {
                    LogUtil.i("onIndicateSuccess")
//                    val testStr = "{\"cardNo\":\"80A8C0F4EA\",\"password\":\"12345678\",\"effectiveTime\":24,\"data\":[{\"taskCode\":\"202401020001\",\"taskId\":\"71b49baa49b343bc84d7e6b829ac1bdc\",\"codeId\":1,\"dataList\":[{\"dataId\":1,\"equipRfidNo\":\"049648B2E31690\",\"infoRfidNo\":\"04E3BCCA201290\",\"target\":1},{\"dataId\":2,\"equipRfidNo\":\"0405982414C563\",\"target\":0,\"prevId\":1}]},{\"taskCode\":\"202401020002\",\"taskId\":\"145b5a4cc38c41e19943f4c8b48d12b0\",\"codeId\":2,\"dataList\":[{\"dataId\":1,\"equipRfidNo\":\"045460F7F4F438\",\"infoRfidNo\":\"04BC6584C65009\",\"target\":1},{\"dataId\":2,\"equipRfidNo\":\"042B99E449E795\",\"target\":0,\"prevId\":1},{\"dataId\":3,\"equipRfidNo\":\"04A312EE848B62\",\"infoRfidNo\":\"04220E86831289\",\"target\":1,\"prevId\":2}]}],\"lockList\":[{\"lockId\":\"1\",\"rfid\":\"040E21443010E9\"},{\"lockId\":\"2\",\"rfid\":\"0457505E5861C2\"}]}"
//                    sendTicket(testStr, it.bleDevice, loadingCallBack)
                    getToken(bleBean, isNeedLoading, prepareDoneCallBack)
                }

                override fun onIndicateFailure(exception: BleException?) {
                    if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, false)))
                    LogUtil.e("onIndicateFailure : ${bleBean.bleDevice.mac} - ${exception?.description}")
                    prepareDoneCallBack?.invoke(false, null)
                }

                override fun onCharacteristicChanged(data: ByteArray?) {
                    LogUtil.i("onCharacteristicChanged ： ${data?.toHexStrings()}")
                    data?.let { itData ->
                        handleRsp(it, itData, isNeedLoading, prepareDoneCallBack)
                    }
                }
            })
        }
    }

    /**
     * 获取蓝牙钥匙token
     */
    private fun getToken(
        bleBean: BleBean?,
        isNeedLoading: Boolean = false,
        prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
    ) {
        if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(true, "开始获取token...", null)))
        bleBean?.let {
            BleCmdManager.getToken(it.bleDevice.mac, object : CustomBleWriteCallback() {
                override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
                    if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "token获取成功", null)))
                    LogUtil.i("getToken success : ${bleBean.bleDevice.mac}")
                }

                override fun onWriteFailure(exception: BleException?) {
                    if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "token获取失败", false)))
                    LogUtil.e("getToken fail : ${bleBean.bleDevice.mac}")
                    prepareDoneCallBack?.invoke(false, null)
                }
            })
        }
    }

    /******************************************蓝牙通用准备结束******************************************/

    fun getBleDeviceByMac(mac: String?): BleBean? {
        return deviceList.find { it.bleDevice.mac == mac }
    }

    /**
     * 下发工作票
     */
    private fun sendTicketBusiness(
        isLock: Boolean,
        mac: String,
        ticketDetail: TicketDetailRespVO,
        lockList: MutableList<String?>?,
        activity: AppCompatActivity,
        isNeedLoading: Boolean = false,
    ) {
        registerConnectListener(mac) { isDone, bleBean ->
            if (!isDone) {
                sendTicketBusiness(isLock, mac, ticketDetail, lockList, activity, isNeedLoading)
                return@registerConnectListener
            }
            if (bleBean == null) {
//                ToastUtils.tip(R.string.simple_key_is_not_connected)
                LogUtil.e("sendTicketBusiness fail : $mac, bleBean is null")
                return@registerConnectListener
            }
            // 单bleBean json赋值
            bleBean.ticketSend = generateTicketSendJson(isLock, ticketDetail, lockList)
            bleBean.ticketSend?.let { itJson ->
                sendTicketWithRetry(itJson, bleBean.bleDevice, isNeedLoading)
            }
        }
    }

    /**
     * 带重试的下发工作票，重试次数3，间隔500ms
     */
    private fun sendTicketWithRetry(
        json: String,
        bleDevice: BleDevice,
        isNeedLoading: Boolean = false,
        maxRetries: Int = 3,
        delayMillis: Long = 500
    ) {
        var retryCount = 0

        fun attemptSend() {
            sendTicket(json, bleDevice, isNeedLoading) { sendRst ->
                if (!sendRst && retryCount < maxRetries) {
                    retryCount++
                    // 等待一段时间后再次尝试
                    Executor.delayOnMain(delayMillis) {
                        LogUtil.i("Retry attempt, mac : ${bleDevice.mac}, retryCount : $retryCount")
                        attemptSend()
                    }
                }
            }
        }

        attemptSend()
    }

    /**
     * 读取工作票完成情况
     */
    private fun getTicketStatusBusiness(
        mac: String,
        isNeedLoading: Boolean = false
    ) {
        registerConnectListener(mac) { isDone, bleBean ->
            if (isDone) {
                Executor.delayOnMain(500) {
                    getTicketStatusWithRetry(bleBean!!.bleDevice, isNeedLoading)
                }
            } else {
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, false)))
            }
        }
    }

    private fun getTicketStatusWithRetry(
        bleDevice: BleDevice,
        isNeedLoading: Boolean = false,
        maxRetries: Int = 3,
        delayMillis: Long = 500
    ) {
        var retryCount = 0

        fun attemptSend() {
            getTicketStatus(bleDevice, isNeedLoading) { sendRst ->
                if (!sendRst && retryCount < maxRetries) {
                    retryCount++
                    // 等待一段时间后再次尝试
                    Executor.delayOnMain(delayMillis) {
                        LogUtil.i("Retry attempt, mac : ${bleDevice.mac}, retryCount : $retryCount")
                        attemptSend()
                    }
                }
            }
        }

        attemptSend()
    }

    private fun sendTicket(jsonStr: String, bleDevice: BleDevice, isNeedLoading: Boolean = false, processCallback: ((Boolean) -> Unit)? = null) {
        if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(true, "开始下发工作票...", null)))
        BleCmdManager.sendWorkTicket(jsonStr, bleDevice = bleDevice, callback = object : CustomBleWriteCallback() {
            override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
                LogUtil.i("sendTicket success")
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(true, "工作票下发中...", null)))
            }

            override fun onWriteFailure(exception: BleException?) {
                LogUtil.e("sendTicket fail : ${bleDevice.mac}")
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "工作票下发失败", null)))
                processCallback?.invoke(false)
            }
        })
    }

    /**
     * 生成下发工作票Json
     *
     * @param vo 工作票详情
     */
    private fun generateTicketSendJson(isLock: Boolean, vo: TicketDetailRespVO, lockList: MutableList<String?>?): String {
        // 用ticketStatus的"待上锁"进行判断
//        var isLock = true
//        vo.ticketStatus?.let {
//            isLock = it.toInt() < Constants.TICKET_STATUS_READY_TO_UNLOCK.toInt()
//        }
        val bo = WorkTicketSendBO(
            cardNo = SPUtils.getLoginUser(MyApplication.instance!!.applicationContext)?.cardNfc,
        )
        CommonUtils.getDiffHours(vo.ticketEndTime)?.let {
            bo.effectiveTime = it
        }
        // 填充默认密码
        bo.password = "123456"
        val dataBO = WorkTicketSendBO.DataBO(
            taskCode = vo.ticketId.toString(),
            codeId = 1
        )
        val taskList = ArrayList<WorkTicketSendBO.DataBO.DataListBO>()
        vo.pointDetailVOList?.let { itList ->
            itList.forEach { pointVO ->
                val task = WorkTicketSendBO.DataBO.DataListBO(
                    dataId = pointVO.pointId?.toInt(),
                    equipRfidNo = pointVO.pointNfc,
                    equipName = pointVO.pointName,
                    target = if (isLock) 0 else 1
                )
                if (!isLock) {
                    task.infoRfidNo = pointVO.lockNfc
                }
                pointVO.prePointId?.let {
                    task.prevId = it.toInt()
                }
                // TODO partCode待补充
                taskList.add(task)
            }
        }
        dataBO.dataList = taskList
        bo.data = mutableListOf(dataBO)
        if (isLock) {
            // TODO 挂锁数组
            if (!lockList.isNullOrEmpty()) {
                bo.lockList = mutableListOf()
                lockList.forEachIndexed { index, s ->
                    bo.lockList?.add(LockListBO(index + 1, s))
                }
            }
        }
        // TODO partList 待补充
        val jsonStr = Gson().toJson(bo)
        LogUtil.i("json : $jsonStr")
        return jsonStr
    }

    fun handleRsp(bleBean: BleBean, byteArray: ByteArray, isNeedLoading: Boolean = false, prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?) {
        // TODO Token校验
//        val len = byteArray[2].toInt()
//        val token = byteArray.copyOfRange(len + 7, len + 11)
//        if (token.contentEquals(bleBean.token)) {
//            LogUtil.i("Token is right")
//        } else {
//            LogUtil.e("Token is wrong")
//        }
        when {
            // 获取令牌
            byteArray.startsWith(BleConst.RSP_GET_TOKEN) -> BleCmdManager.handleToken(bleBean.bleDevice, byteArray) { isSuccess ->
                if (isSuccess) {
                    prepareDoneCallBack?.invoke(true, bleBean)
                }
            }
            // 工作模式切换
            byteArray.startsWith(BleConst.RSP_SWITCH_MODE) -> {
                handleSwitchModeResult(byteArray, isNeedLoading) { res, job ->
                    mEventBus.postValue(MsgEvent(MSG_EVENT_SWITCH_MODE, SwitchModeMsg(job.toInt(), res.toInt(), bleBean)))
                }
            }
            // 工作票下发
            byteArray.startsWith(BleConst.RSP_SEND_WORK_TICKET) -> handleWorkTicketResult(bleBean, byteArray, isNeedLoading)
            // 获取设备当前状态
            byteArray.startsWith(BleConst.RSP_CURRENT_STATUS) -> BleCmdManager.handleCurrentStatus(byteArray) {
                mEventBus.postValue(MsgEvent(MSG_EVENT_CURRENT_MODE, CurrentModeMsg(bleBean, it)))
            }
            // 获取设备工作票完成情况
            byteArray.startsWith(BleConst.RSP_WORK_TICKET_RESULT) && byteArray[3] == 0x02.toByte() ->
                handleTicketStatus(bleBean.bleDevice, byteArray, isNeedLoading)
        }
    }

    /**
     * 工作模式切换结果
     * job : 0x01：工作模式 0x02：待机模式
     * res : 0x01：成功 0x02：失败
     */
    private fun handleSwitchModeResult(byteArray: ByteArray, isNeedLoading: Boolean = false, callBack: ((Byte, Byte) -> Unit)? = null) {
        BleCmdManager.handleSwitchModeResult(byteArray) { job, res ->
            if (res == 0x01.toByte() && job == 0x01.toByte()) {
                LogUtil.i("切换工作模式成功")
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "切换工作模式成功", null)))
            } else if (res == 0x01.toByte() && job == 0x02.toByte()) {
                LogUtil.i("切换待机模式成功")
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "切换待机模式成功", null)))
            } else {
                LogUtil.e("切换模式失败 : ${job.toInt()} - ${res.toInt()}")
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, null)))
            }
            callBack?.invoke(res, job)
        }
    }

    /**
     * 工作票下发结果
     * res：0x00：成功 0x01：失败 0x02：传输超时 0x0D：当前IDX超出范围 0x0E：当前数据CRC校验失败 0x14：JSON结构错误 0x63：未知错误
     */
    private fun handleWorkTicketResult(bleBean: BleBean, byteArray: ByteArray, isNeedLoading: Boolean = false) {
        BleCmdManager.handleWorkTicketResult(bleBean, byteArray) { isSuccess, rst ->
            if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, null, null)))
            if (isSuccess) {
                // 下发完毕，切换工作模式
                LogUtil.i("工作票下发完毕")
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(true, "切换钥匙为工作模式", null)))

                Executor.delayOnIO(800) {
                    switchWorkMode(bleBean.bleDevice, isNeedLoading)
                }
            }
        }
    }

    fun getCurrentStatus(from: Int, bleDevice: BleDevice) {
        LogUtil.i("getCurrentStatus - ${bleDevice.mac} - from : $from")
        BleCmdManager.getCurrentStatus(bleDevice, object : CustomBleWriteCallback() {
            override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
                LogUtil.i("getCurrentStatus success : ${bleDevice.mac}")
            }

            override fun onWriteFailure(exception: BleException?) {
                LogUtil.i("getCurrentStatus fail : ${bleDevice.mac}")
                Executor.delayOnMain(1000) {
                    getCurrentStatus(from, bleDevice)
                }
            }
        })
    }

    private fun switchWorkMode(bleDevice: BleDevice, isNeedLoading: Boolean = false) {
        LogUtil.i("switchWorkMode - ${bleDevice.mac}")
        BleCmdManager.switchMode(STATUS_WORK, bleDevice, object : CustomBleWriteCallback() {
            override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
                LogUtil.i("switch mode work success : ${bleDevice.mac}")
            }
            override fun onWriteFailure(exception: BleException?) {
                LogUtil.e("switch mode work fail : ${exception?.code} - ${exception?.description}")
                Executor.delayOnMain(500) {
                    switchWorkMode(bleDevice, isNeedLoading)
                }
            }
        })
    }

    /**
     * 处理工作票完成情况
     */
    private fun handleTicketStatus(bleDevice: BleDevice, byteArray: ByteArray, isNeedLoading: Boolean = false) {
        BleCmdManager.handleTicketStatus(bleDevice, byteArray) { ticketJson ->
            if (ticketJson.isNullOrEmpty()) {
                return@handleTicketStatus
            }
            if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "工作票完成状态读取完成", null)))
            LogUtil.i("Get ticket status complete : ${bleDevice.mac}")
            // TD:Ticket Done
            if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "TD$ticketJson}", true)))

            val workTicketGetBO = Gson().fromJson(ticketJson, WorkTicketGetBO::class.java)

            // 判断workTicketGetBO里是否有未完成的
            if (workTicketGetBO.hasFinished()) {
                handleKeyReturn(bleDevice, workTicketGetBO)
            } else {
                showKeyReturnDialog({
                    handleKeyReturn(bleDevice, workTicketGetBO)
                }) {
                    BleManager.getInstance().disconnect(bleDevice)
                }
            }
        }
    }

    private fun handleKeyReturn(bleDevice: BleDevice, workTicketGetBO: WorkTicketGetBO?) {
        // 确认归还，切换为待机模式
        switchReadyMode(bleDevice)

        val dock = ModBusController.getDockByKeyMac(bleDevice.mac)
        val keyBean = dock?.getKeyList()?.find { it.mac == bleDevice.mac }
        keyBean?.let {
            ModBusController.controlKeyBuckle(false, keyBean.isLeft, dock.addr)
        }

        // 上报隔离点状态
        val keyNfc = ModBusController.getKeyByMac(bleDevice.mac)?.rfid
        workTicketGetBO?.data?.forEach { data ->
            val updateList = mutableListOf<LockPointUpdateReqVO>()
            data.dataList?.forEach { dataListDTO ->
                val updateVO = LockPointUpdateReqVO(
                    data.taskCode?.toLong(),
                    dataListDTO.infoRfidNo,
                    dataListDTO.equipRfidNo,
                    keyNfc!!,
                    dataListDTO.target,
                    dataListDTO.status
                )
                updateList.add(updateVO)
            }

            // 上报点位钥匙绑定
            NetApi.updateLockPointBatch(updateList) { isSuccess ->
                data.taskCode?.toLong()?.let {
                    mEventBus.postValue(MsgEvent(MSG_EVENT_UPDATE_TICKET_PROGRESS, UpdateTicketProgressMsg(it)))
                }
            }

            // 上报钥匙归还
            NetApi.updateKeyReturn(data.taskCode?.toLong()!!, keyNfc!!, MyApplication.instance!!.serialNo()) { isSuccess ->

            }
        }
    }

    private fun switchReadyMode(bleDevice: BleDevice) {
        BleCmdManager.switchMode(STATUS_READY, bleDevice, object : CustomBleWriteCallback() {
            override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
                LogUtil.i("switch mode ready success : ${bleDevice.mac}")
            }

            override fun onWriteFailure(exception: BleException?) {
                LogUtil.e("switch mode ready fail : ${bleDevice.mac}")
                Executor.delayOnMain(300) {
                    switchReadyMode(bleDevice)
                }
            }
        })
    }

    /**
     * 获取工作票完成情况
     */
    private fun getTicketStatus(bleDevice: BleDevice, isNeedLoading: Boolean = false, processCallback: ((Boolean) -> Unit)? = null) {
        if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(true, "开始获取工作票", null)))
        BleCmdManager.getTicketStatus(bleDevice, object : CustomBleWriteCallback() {
            override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "工作票获取成功", null)))
                LogUtil.i("getTicketStatus success")}
            override fun onWriteFailure(exception: BleException?) {
                if (isNeedLoading) mEventBus.postValue(MsgEvent(MSG_EVENT_LOADING, LoadingMsg(false, "工作票获取失败", false)))
                processCallback?.invoke(false)
                LogUtil.e("getTicketStatus fail")}
        })
    }

    /**
     * 添加待更新取出状态的设备
     */
    fun addDeviceTake(deviceType: Int, ticketId: Long, nfc: String?) {
        LogUtil.i("$deviceType - $ticketId - $nfc")
        mDeviceTakeList.removeIf { it.deviceType == deviceType && it.nfc == nfc }
        mDeviceTakeList.add(DeviceTakeUpdateBO(deviceType, ticketId, nfc!!))
    }

    private fun handleDeviceTake(deviceTakeUpdateBO: DeviceTakeUpdateMsg) {
        LogUtil.i("$deviceTakeUpdateBO")
        when (deviceTakeUpdateBO.deviceType) {
            // 钥匙
            0 -> {
                mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_KEY && it.nfc == deviceTakeUpdateBO.nfc }?.let { info ->
                    NetApi.updateKeyTake(info.ticketId, info.nfc, MyApplication.instance?.serialNo()!!) { isSuccess ->
                        if (isSuccess) {
                            mDeviceTakeList.removeIf { it.deviceType == DEVICE_TYPE_KEY && it.nfc == info.nfc }
                        }
                    }
                }
            }
            // 挂锁
            1 -> {
                mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_LOCK && it.nfc == deviceTakeUpdateBO.nfc }?.let { info ->
                    NetApi.updateLockTake(mutableListOf(LockTakeUpdateReqVO(info.ticketId, info.nfc, MyApplication.instance?.serialNo()!!))) { isSuccess ->
                        if (isSuccess == true) {
                            // 检查是不是要发钥匙了
                            mDeviceTakeList.removeIf { it.deviceType == DEVICE_TYPE_LOCK && it.nfc == info.nfc }
                            // 检查当前工作票是否取完挂锁
                            if (mDeviceTakeList.any { it.deviceType == DEVICE_TYPE_LOCK && it.ticketId == info.ticketId }) {
                                LogUtil.i("等待所有挂锁取出")
                                return@updateLockTake
                            }
                            // 检查有无当前工作票的钥匙
                            mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_KEY && it.ticketId == info.ticketId }?.let { itKey ->
                                getCurrentStatus(2, getBleDeviceByMac(ModBusController.getKeyByRfid(itKey.nfc)?.mac)!!.bleDevice)
                            }
                        }
                    }
                }
            }
        }
    }

    private fun handleCurrentMode(currentModeMsg: CurrentModeMsg) {
        when (currentModeMsg.mode) {
            // 工作模式
            0x01.toByte() -> {
                // 读工作票
                getTicketStatusBusiness(currentModeMsg.bleBean.bleDevice.mac)
            }
            // 待机模式
            0x02.toByte() -> {
                // 根据情况看是否需要下发工作票
                ModBusController.getKeyByMac(currentModeMsg.bleBean.bleDevice.mac)?.let { key ->
                    // 判断是否有待取的钥匙
                    val updateBo = mDeviceTakeList.find { it.deviceType == DEVICE_TYPE_KEY && key.rfid == it.nfc }
                    updateBo?.let { itBO ->
                        NetApi.getStepDetail(itBO.ticketId) {
                            var step = 0
                            it?.filter { it.stepStatus == "1" }?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
                                step = it
                            }
                            NetApi.getTicketDetail(itBO.ticketId) { ticketDetail ->
                                val role = ticketDetail?.jobTicketUserList?.find {
                                    it.userId == SPUtils.getLoginUser(MyApplication.instance?.applicationContext!!)?.userId && it.userType == USER_TYPE_LOCKER
                                }
                                if (role == null) {
                                    ToastUtils.tip(R.string.you_are_not_locker_tip)
                                    return@getTicketDetail
                                }
                                if (step == 4) {    // 上锁工作票
                                    NetApi.getTicketEquipDetail(itBO.ticketId) { equipDetail ->
                                        sendTicketBusiness(
                                            true,
                                            currentModeMsg.bleBean.bleDevice.mac,
                                            ticketDetail,
                                            equipDetail?.ticketLockVOList?.map { it.lockNfc }?.toMutableList(),
                                            ActivityUtils.currentActivity() as BaseActivity<*>,
                                            true
                                        )
                                    }
                                } else if (step == 7) { // 解锁工作票
                                    sendTicketBusiness(
                                        false,
                                        currentModeMsg.bleBean.bleDevice.mac,
                                        ticketDetail,
                                        null,
                                        ActivityUtils.currentActivity() as BaseActivity<*>,
                                        true
                                    )
                                }
                            }
                        }
                    }
                }
            }
            // 故障模式
            0x03.toByte() -> {
                // TODO 上报？
                ToastUtils.tip("${currentModeMsg.bleBean.bleDevice.mac} : " +
                        "${MyApplication.instance?.applicationContext?.getString(R.string.key_is_in_failure_mode)}"
                )
            }
        }
    }
}