package com.grkj.iscs.ble

import com.clj.fastble.data.BleDevice
import com.clj.fastble.exception.BleException
import com.grkj.iscs.BusinessManager
import com.grkj.iscs.BusinessManager.mEventBus
import com.grkj.iscs.ble.BleConst.REQ_CURRENT_STATUS
import com.grkj.iscs.ble.BleConst.REQ_GET_TOKEN
import com.grkj.iscs.ble.BleConst.REQ_GET_VERSION
import com.grkj.iscs.ble.BleConst.REQ_POWER_STATUS
import com.grkj.iscs.ble.BleConst.REQ_SEND_WORK_TICKET
import com.grkj.iscs.ble.BleConst.REQ_SWITCH_MODE
import com.grkj.iscs.ble.BleConst.REQ_TRANSFER_FILE
import com.grkj.iscs.ble.BleConst.REQ_WORK_TICKET_RESULT
import com.grkj.iscs.ble.BleConst.REQ_WORK_TICKET_RESULT_PART
import com.grkj.iscs.ble.BleConst.WRITE_UUID
import com.grkj.iscs.extentions.crc16
import com.grkj.iscs.extentions.startsWith
import com.grkj.iscs.extentions.toByteArray
import com.grkj.iscs.extentions.toHexStrings
import com.grkj.iscs.model.eventmsg.GetTicketStatusMsg
import com.grkj.iscs.model.eventmsg.MsgEvent
import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_GET_TICKET_STATUS
import com.grkj.iscs.util.Executor
import com.grkj.iscs.util.log.LogUtil
import java.io.File

/**
 * 指令操作类
 */
object BleCmdManager {

    /**
     * 拼接时间戳
     */
    private fun assembleTimeStamp(byteArray: ByteArray): ByteArray {
        return byteArray + getTimeStamp()
    }

    /**
     * 拼接时间戳 + token
     */
     private fun assembleData(bleBean: BleBean, byteArray: ByteArray): ByteArray? {
        bleBean.token?.let {
            return assembleTimeStamp(byteArray) + it
        } ?: run {
            // TODO 有问题，一直循环
//            getToken(bleBean.bleDevice.mac, object : CustomBleWriteCallback() {
//                override fun onPrompt(promptStr: String?) {}
//
//                override fun onConnectPrompt(promptStr: String?) {}
//
//                override fun onDisConnectPrompt(promptStr: String?) {}
//
//                override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {}
//
//                override fun onWriteFailure(exception: BleException?) {}
//
//            })
//            // TODO 临时方案
//            Thread.sleep(100)
//            return assembleData(bleBean, byteArray)

            return null
        }
    }

    private fun getTimeStamp(): ByteArray {
        val tempArr = (System.currentTimeMillis() / 1000).toByteArray()
        val timeStampArr = byteArrayOf(tempArr[0], tempArr[1], tempArr[2], tempArr[3])
        return timeStampArr
    }

    fun handleRsp(bleBean: BleBean, byteArray: ByteArray) {
//        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) -> handleToken(bleBean.bleDevice, byteArray)
            // 工作模式切换
            byteArray.startsWith(BleConst.RSP_SWITCH_MODE) -> handleSwitchModeResult(byteArray)
            // 工作票下发
            byteArray.startsWith(BleConst.RSP_SEND_WORK_TICKET) -> handleWorkTicketResult(bleBean, byteArray)
            // 获取设备当前状态
            byteArray.startsWith(BleConst.RSP_CURRENT_STATUS) -> handleCurrentStatus(byteArray)
            // 获取钥匙电量
            byteArray.startsWith(BleConst.RSP_POWER_STATUS) -> handlePowerStatus(byteArray)
            // 传输文件
            byteArray.startsWith(BleConst.RSP_TRANSFER_FILE) && byteArray[3] == 0x01.toByte() -> handleFileRsp(bleBean, byteArray)
            // 获取固件版本号
            byteArray.startsWith(BleConst.RSP_GET_VERSION) -> handleVersion(byteArray)
            // 获取设备工作票完成情况
            byteArray.startsWith(BleConst.RSP_WORK_TICKET_RESULT) && byteArray[3] == 0x02.toByte() ->
                handleTicketStatus(bleBean.bleDevice, byteArray)
        }
    }

    /**
     * 获取令牌
     */
    fun getToken(mac: String?, callback: CustomBleWriteCallback?) {
        LogUtil.i("$mac")
        BusinessManager.getBleDeviceByMac(mac)?.bleDevice?.let {
            LogUtil.i("Get token : $mac")
            BleUtil.instance?.write(it, cmd = assembleTimeStamp(REQ_GET_TOKEN), writeCallback = callback)
        }
    }

    /**
     * 令牌处理
     *
     * @param callBack 是否成功
     */
    fun handleToken(bleDevice: BleDevice, byteArray: ByteArray, callBack: ((Boolean) -> Unit)? = null) {
        LogUtil.i("handleToken : ${byteArray.toHexStrings()}")
        BusinessManager.getBleDeviceByMac(bleDevice.mac)?.let {
            it.token = byteArrayOf(byteArray[11], byteArray[12], byteArray[13], byteArray[14])
            callBack?.invoke(true)
            LogUtil.i("Token 赋值 ${it.token?.toHexStrings()} : ${bleDevice.mac}")
        } ?: let {
            callBack?.invoke(false)
        }
    }

    /**
     * 工作模式切换
     *
     * @param mode 0x01：工作模式 0x02：待机模式
     */
    fun switchMode(mode: ByteArray, bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
        BusinessManager.getBleDeviceByMac(bleDevice.mac)?.let {
            BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_SWITCH_MODE + mode), writeCallback = callback)
        }
    }

    /**
     * 工作模式切换结果
     * job : 0x01：工作模式 0x02：待机模式
     * res : 0x01：成功 0x02：失败
     */
    fun handleSwitchModeResult(byteArray: ByteArray, callBack: ((Byte, Byte) -> Unit)? = null) {
        LogUtil.i("handleSwitchModeResult : ${byteArray.toHexStrings()}")
        val job = byteArray[4]
        val res = byteArray[5]
        callBack?.invoke(job, res)
    }

    /**
     * 工作票下发
     */
    fun sendWorkTicket(json: String, idx: Int = 0, bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
        LogUtil.i("sendWorkTicket : $idx")
        BusinessManager.getBleDeviceByMac(bleDevice.mac)?.let {
            it.ticketSend = json
        }
        val totalLength = json.toByteArray().size
        val totalPackets = (totalLength + 128 - 1) / 128
        val total = totalPackets.toByteArray()

        val data = if (idx == totalPackets - 1) {
            json.toByteArray().copyOfRange(idx * 128, totalLength)
        } else {
            json.toByteArray().copyOfRange(idx * 128, (idx + 1) * 128)
        }
//        val jsonInfo = total + idx.toByteArray() + CRC16.crc16(data, 0, data.size - 1).toByteArray() + data.size.toByteArray() + data
        val jsonInfo = total + idx.toByteArray() + data.crc16(0, data.size) + data.size.toByteArray() + data
        LogUtil.d("debug1 : ${total.size} : ${idx.toByteArray().size} : ${data.crc16(0, data.size).size} : ${data.size.toByteArray().size} : ${data.size}")
        LogUtil.d("debug2 : ${(jsonInfo.size + 1).toByteArray(1).size} : ${0x02.toByteArray(1).size} : ${jsonInfo.size}")

        val cmd = REQ_SEND_WORK_TICKET + (jsonInfo.size + 1).toByteArray(1) + 0x02.toByteArray(1) + jsonInfo

        LogUtil.d("debug3 : ${cmd.toHexStrings()}")

        BusinessManager.getBleDeviceByMac(bleDevice.mac)?.let {
            BleUtil.instance?.write(it.bleDevice, writeUUID = WRITE_UUID, cmd = assembleData(it, cmd), writeCallback = callback)
        }
    }

    /**
     * 工作票下发结果
     * res：0x00：成功 0x01：失败 0x02：传输超时 0x0D：当前IDX超出范围 0x0E：当前数据CRC校验失败 0x14：JSON结构错误 0x63：未知错误
     *
     * @param callBack 是否成功、结果
     */
    fun handleWorkTicketResult(bleBean: BleBean, byteArray: ByteArray, callBack: ((Boolean, Byte?) -> Unit)? = null) {
        LogUtil.i("handleWorkTicketResult : ${byteArray.toHexStrings()}")
        val idx = byteArray[4] + byteArray[5]
        val total = byteArray[6] + byteArray[7]
        val res = byteArray[8]
        when (res) {
            0x00.toByte() -> LogUtil.i("Work ticket send success")
            0x01.toByte() -> LogUtil.i("Work ticket send fail")
            0x02.toByte() -> LogUtil.i("Work ticket send timeout")
            0x0D.toByte() -> LogUtil.i("Work ticket send idx out of range")
            0x0E.toByte() -> LogUtil.i("Work ticket send data crc error")
            0x14.toByte() -> LogUtil.i("Work ticket send json error")
        }
        LogUtil.i("idx : $idx : $total : $res")
        if (idx != total - 1) {
            if (res == 0x00.toByte() || res == 0x02.toByte()) {
                // TODO 要判断res
                sendWorkTicket(
                    BusinessManager.getBleDeviceByMac(bleBean.bleDevice.mac)?.ticketSend!!,
                    if (res == 0x00.toByte()) idx + 1 else idx,
                    bleBean.bleDevice,
                    object : CustomBleWriteCallback() {
                        override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {}

                        override fun onWriteFailure(exception: BleException?) {}
                    })
            } else {
                callBack?.invoke(false, res)
            }
        } else {
            if (res == 0x00.toByte()) {
                LogUtil.i("Work ticket is done")
                callBack?.invoke(true, res)
            } else {
                callBack?.invoke(false, res)
            }
        }
    }

    /**
     * 获取设备当前状态
     */
    fun getCurrentStatus(bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
        BusinessManager.getBleDeviceByMac(bleDevice.mac)?.let {
            BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_CURRENT_STATUS), writeCallback = callback)
        }
    }

    /**
     * 处理设备当前状态
     * 0x01：工作模式 0x02：待机模式 0x03：故障状态
     */
    fun handleCurrentStatus(byteArray: ByteArray, callBack: ((Byte) -> Unit)? = null) {
        LogUtil.i("handleCurrentStatus : ${byteArray.toHexStrings()}")
        val job = byteArray[4]
        when (job) {
            0x01.toByte() -> {
                LogUtil.i("handleCurrentStatus : 工作模式")
            }
            0x02.toByte() -> {
                LogUtil.i("handleCurrentStatus : 待机模式")
            }
            0x03.toByte() -> {
                LogUtil.i("handleCurrentStatus : 故障状态")
            }
        }
        callBack?.invoke(job)
    }

    /**
     * 获取工作票完成情况
     */
    fun getTicketStatus(bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
        BusinessManager.getBleDeviceByMac(bleDevice.mac)?.let {
            BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_WORK_TICKET_RESULT), writeCallback = callback)
        }
    }

    /**
     * 处理工作票完成情况
     */
    fun handleTicketStatus(bleDevice: BleDevice, byteArray: ByteArray, callBack: ((String?) -> Unit)? = null) {
        // TODO 需要有超时重传机制
        LogUtil.i("handleTicketStatus : ${byteArray.toHexStrings()}")

        val total = byteArray[4] + byteArray[5]
        val idx = byteArray[6] + byteArray[7]
        val crc = byteArray[8] + byteArray[9]
        val size = byteArray[10].toUByte() + byteArray[11].toUByte()
        LogUtil.i("工作票数据 ： $total : $idx : $size")
        // 数据组装
        BusinessManager.getBleDeviceByMac(bleDevice.mac)?.let {
            it.ticketStatus += byteArray.copyOfRange(12, 12 + size.toInt())
        }
        // TODO 缺少res处理
        if (idx != total - 1) {
            getTicketStatusPart(idx.toByteArray(), total.toByteArray(), byteArrayOf(0x00.toByte()), bleDevice, object : CustomBleWriteCallback() {
                override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
                    LogUtil.i("getTicketStatusPart success")
                }

                override fun onWriteFailure(exception: BleException?) {
                    LogUtil.e("getTicketStatusPart fail")
                    mEventBus.postValue(MsgEvent(MSG_EVENT_GET_TICKET_STATUS, GetTicketStatusMsg(false, bleDevice)))
                }
            })
        } else {
            BusinessManager.getBleDeviceByMac(bleDevice.mac)?.let {
                LogUtil.i("工作票完成接收 ： ${String(it.ticketStatus)}")
                callBack?.invoke(String(it.ticketStatus))
                // TODO 清空ticket
                it.ticketStatus = byteArrayOf()
            } ?: let {
                callBack?.invoke(null)
            }
        }
    }

    /**
     * 获取工作票完成情况分包
     */
    private fun getTicketStatusPart(idx: ByteArray, total: ByteArray, res: ByteArray, bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
        BusinessManager.getBleDeviceByMac(bleDevice.mac)?.let {
            BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_WORK_TICKET_RESULT_PART + idx + total + res), writeCallback = callback)
        }
    }

    /**
     * 获取钥匙电量
     */
    fun getPower(mac: String?, callback: CustomBleWriteCallback?) {
        BusinessManager.getBleDeviceByMac(mac)?.let {
            BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_POWER_STATUS), writeCallback = callback)
        }
    }

    /**
     * 处理钥匙电量
     * bat：电量百分比，范围 0-100，单位：%
     * chg：0x01：未充电 0x02：充电中 0x03：充满
     */
    private fun handlePowerStatus(byteArray: ByteArray) {
        LogUtil.i("handlePowerStatus : ${byteArray.toHexStrings()}")
        val bat = byteArray[4].toInt()
        val chg = byteArray[5]
        LogUtil.i("钥匙电量 ： $bat%")
        when (chg) {
            0x01.toByte() -> {
                LogUtil.i("充电状态：未充电")
            }
            0x02.toByte() -> {
                LogUtil.i("充电状态：充电中")
            }
            0x03.toByte() -> {
                LogUtil.i("充电状态：充满")
            }
        }
    }

    /**
     * 发送文件
     * type： 1：固件文件 2：点位PNG文件
     * FLNM：文件名（不含扩展名）
     * FLSZ：文件大小（字节）
     * FLCRC：文件的CRC-16
     * PGTOTAL：文件总包数
     * PGIDX：当前包idx
     * PGCRC：当前包CRC-16
     * PGSZ：当前包长度（字节）
     * PGDATA：当前包数据
     */
    fun sendFile(type: Int, file: File, idx: Int = 0, mac: String?, callback: CustomBleWriteCallback?) {
        Executor.runOnIO {
            LogUtil.i("sendFile : $idx")

            BusinessManager.getBleDeviceByMac(mac)?.let {
                it.fileSend = file
            }

            val pgtotal = (file.readBytes().size + 128 - 1) / 128
            if (idx == pgtotal) {
                LogUtil.i("Send finish")
                return@runOnIO
            }

            val flnm = file.name.substringBeforeLast(".").toByteArray(8)
            val flsz = file.readBytes().size.toByteArray(4)
            val flcrc = file.readBytes().crc16()
            val pgdata = if (idx == pgtotal - 1) {
                file.readBytes().copyOfRange(idx * 128, file.readBytes().size - 1)
            } else {
                file.readBytes().copyOfRange(idx * 128, (idx + 1) * 128)
            }
            val pgsz = pgdata.size.toByteArray()
            val pgcrc = pgdata.crc16()

            val fileInfo = byteArrayOf(type.toByte()) + flnm + flsz + flcrc + pgtotal.toByteArray() + idx.toByteArray() + pgcrc + pgsz + pgdata
//        println("______________________________________________________________________________")
//        println("${file.readBytes().size}")
//        println("${byteArrayOf(type.toByte()).size} : ${flnm.size} : ${flsz.size} : ${flcrc.size} : ${pgtotal.toByteArray().size} : ${idx.toByteArray().size} : ${pgcrc.size} : ${pgsz.size} : ${pgdata.size}")
//        println("______________________________________________________________________________")
//        println("file info size : ${fileInfo.size}")
            val cmd = REQ_TRANSFER_FILE + (fileInfo.size + 1).toByteArray(1) + 0x01.toByteArray(1) + fileInfo
//        println("cmd size : ${REQ_TRANSFER_FILE.size} : ${(fileInfo.size + 1).toByteArray(1).size} : ${0x01.toByteArray(1).size} : ${fileInfo.size}")

            BusinessManager.getBleDeviceByMac(mac)?.let {
                BleUtil.instance?.write(it.bleDevice, writeUUID = WRITE_UUID, cmd = assembleData(it, cmd), writeCallback = callback)
            }
            Thread.sleep(50)
            sendFile(type, file, idx + 1, mac, callback)
        }
    }

    /**
     * 处理发送分包文件响应
     * type： 0x01：固件文件 0x02：点位PNG文件
     */
    private fun handleFileRsp(bleBean: BleBean, byteArray: ByteArray) {
        LogUtil.i("handleFileRsp : ${byteArray.toHexStrings()}")
        val type = byteArray[4]
        val res = byteArray[17]
        val total = byteArray[15] + byteArray[16]
        val idx = byteArray[13] + byteArray[14]
        if (idx != total - 1 && (res == 0x00.toByte() || res == 0x02.toByte())) {
            // 不用等回复再发
        }
    }

    /**
     * 获取版本
     */
    fun getVersion(mac: String?, callback: CustomBleWriteCallback?) {
        BusinessManager.getBleDeviceByMac(mac)?.let {
            BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_GET_VERSION), writeCallback = callback)
        }
    }

    /**
     * 处理软件/硬件版本
     */
    private fun handleVersion(byteArray: ByteArray) {
        val sofVersion = parseVersion(byteArray[4])
        val hardVersion = parseVersion(byteArray[5])
        LogUtil.i("$sofVersion : $hardVersion")
    }

    /**
     * 版本解析
     */
    private fun parseVersion(byte: Byte): String {
        // 将 Byte 转换为 Int 以便更容易进行位操作
        val intValue = byte.toInt()
        // 提取高 4 位作为主版本号
        val majorVersion = (intValue and 0xF0) ushr 4
        // 提取低 4 位作为次版本号
        val minorVersion = intValue and 0x0F

        return "V$majorVersion.$minorVersion"
    }
}