package com.abbidot.tracker.util.bluetooth

import android.text.TextUtils
import com.abbidot.tracker.bean.FencesBean
import com.abbidot.tracker.bean.WiFiZoneBean
import com.abbidot.tracker.constant.ConstantInt
import java.util.TimeZone
import kotlin.experimental.xor


/**
 *Created  by .yzq on 2021/12/1/001.
 * @link
 * @description: 蓝牙cmd命令
 */
class SRBleCmdUtil private constructor() {

    companion object {
        val instance: SRBleCmdUtil by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            SRBleCmdUtil()
        }

        /**
         * 写指令
         */
        const val CMD_WRITE = 1

        /**
         * 读指令
         */
        const val CMD_READ = 0
    }

    /**
     * java 写法
     *
     *      public  byte calcCrc8(byte[] data) {
    byte crc = 0;
    for (int j = 0; j < data.length; j++) {
    crc ^= data[j];
    for (int i = 0; i < 8; i++) {
    if ((crc & 0x01) != 0) {
    crc = (byte) ((crc) >> 1);
    crc ^= 0x8c;
    } else {
    crc = (byte) ((crc) >> 1);
    }
    }
    }
    return crc;
    }
     *
     *  CRC8 算法
     */
    private fun calcCrc8(data: ByteArray): Byte {
        var crc: Byte = 0
        for (j in data.indices) {
            crc = crc xor data[j]
            for (i in 0..7) {
                if (byteToInt(crc) and 0x01 != 0) {
                    crc = (byteToInt(crc) shr 1).toByte()
                    crc = crc xor 0x8c.toByte()
                } else {
                    crc = (byteToInt(crc) shr 1).toByte()
                }
            }
        }
        return crc
    }

    /**
     *  CRC8 算法
     */
    private fun getCrc8(data: ByteArray): Byte {
        return calcCrc8(data)
    }

    /**
     * 将十六进制字符串转换为字节数组
     */
    private fun hexStringToByteArray(hexString: String): ByteArray {
        require(hexString.length % 2 == 0) { "十六进制字符串长度必须为偶数" }
        return ByteArray(hexString.length / 2) { i ->
            val startIndex = i * 2
            hexString.substring(startIndex, startIndex + 2).toInt(16).toByte()
        }
    }

    /**
     * 长整型转换高低4个字节
     */
    fun longTo4ByteArray(value: Long): ByteArray {
        val byte1 = (value shr 24 and 0xffL).toByte()
        val byte2 = (value shr 16 and 0xffL).toByte()
        val byte3 = (value shr 8 and 0xffL).toByte()
        val byte4 = (value and 0xffL).toByte()
        return byteArrayOf(byte1, byte2, byte3, byte4)
    }

    /**
     * 高低4个字节转换长整型
     */
    fun byte4ArrayToLong(data: ByteArray): Long {
        if (data.size == 4) {
            return (data[0].toLong() and 0xffL shl 24) or (data[1].toLong() and 0xffL shl 16) or (data[2].toLong() and 0xffL shl 8) or (data[3].toLong() and 0xffL)
        }
        return 0L
    }

    /**
     * 高低2个字节转换长整型
     */
    fun byte2ArrayToInt(data: ByteArray): Int {
        if (data.size == 2) {
            return (data[0].toInt() and 0xff shl 8) or (data[1].toInt() and 0xff)
        }
        return 0
    }

    /**
     * 长整型转换高低2个字节
     */
    private fun longTo2ByteArray(value: Long): ByteArray {
        val byte1 = (value shr 8 and 0xffL).toByte()
        val byte2 = (value and 0xffL).toByte()
        return byteArrayOf(byte1, byte2)
    }

    /**
     * byte转int
     */
    fun byteToInt(byte: Byte): Int {
        return byte.toInt() and 0xff
    }

    /**
     * 获取最终完整加密命令
     */
    private fun getCrc8Cmd(byteArray: ByteArray): ByteArray {
        val crc8 = getCrc8(byteArray)
        //后面追加
        return byteArray.plus(crc8)
    }

    /**
     * 绑定设备
     */
    fun bindDevice(): ByteArray {
        val byteArray = byteArrayOf(0x01, CMD_WRITE.toByte(), 0x02, 0, 0)
        return getCrc8Cmd(byteArray)
    }

    /**
     * 彩灯颜色设置/查询消息
     */
    fun ledColor(readOrWrite: Int, R: Int, G: Int, B: Int): ByteArray {
        val byteArray = byteArrayOf(0x02, readOrWrite.toByte(), R.toByte(), G.toByte(), B.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 彩灯状态设置/查询消息
     */
    fun ledState(readOrWrite: Int, state: Int): ByteArray {
        val byteArray = byteArrayOf(0x03, readOrWrite.toByte(), state.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 激活设备
     */
    fun activeDevice(): ByteArray {
        val byteArray = byteArrayOf(0x05, CMD_WRITE.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 关机，设备会上报关机状态后关机
     */
    fun shutdownDevice(): ByteArray {
        val byteArray = byteArrayOf(0x04, CMD_WRITE.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 强制关机消息,设备不会上报，立马关机
     */
    fun forcedShutdown(): ByteArray {
        val byteArray = byteArrayOf(0x18, CMD_WRITE.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 获取固件版本号
     */
    fun getFirmwareVersion(): ByteArray {
        val byteArray = byteArrayOf(0x09, CMD_READ.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 获取WiFi列表
     */
    fun getWiFiZoneList(): ByteArray {
        val byteArray = byteArrayOf(0x0f, CMD_READ.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * Mac地址转字节数组
     */
    private fun macToByte(wifiMac: String): ByteArray {
        var byteArray = byteArrayOf()
        if (TextUtils.isEmpty(wifiMac)) return byteArray
        val macs = wifiMac.split(":")
        for (c in macs) {
            val hexValue = c.toInt(16)
            byteArray = byteArray.plus(hexValue.toByte())
        }
        return byteArray
    }

    /**
     * 4.16 设置WiFi 0x10
     */
    fun setWiFiZone(wiFiZoneBean: WiFiZoneBean): ByteArray {
        wiFiZoneBean.apply {
            var byteArray = byteArrayOf(0x10, CMD_WRITE.toByte())
            byteArray = byteArray.plus(macToByte(wifiMac))
            val lonArray = longTo4ByteArray((longitude * 1000000L).toLong())
            val latArray = longTo4ByteArray((latitude * 1000000L).toLong())
            byteArray = byteArray.plus(lonArray)
            byteArray = byteArray.plus(latArray)
            return getCrc8Cmd(byteArray)
        }
    }

    /**
     * 4.17 删除WiFi 0x11
     */
    fun deleteWiFiZone(wifiMac: String): ByteArray {
        var byteArray = byteArrayOf(0x11, CMD_WRITE.toByte())
        byteArray = byteArray.plus(macToByte(wifiMac))
        return getCrc8Cmd(byteArray)
    }

    /**
     * 设置时区
     */
    fun setTime(): ByteArray {
        val currentTime = System.currentTimeMillis() / 1000
        val timeMillisByte = longTo4ByteArray(currentTime)

        val tz = TimeZone.getDefault()
        //为了不出现负数，数值=实际时区+12
        val timeZone = tz.getOffset(System.currentTimeMillis()) / (1000 * 60 * 60) + 12

        val byteArray = byteArrayOf(
            0x16, CMD_WRITE.toByte()
        ).plus(timeMillisByte).plus((timeZone and 0xff).toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 4.23 参数同步提醒消息 0x017
     */
    fun setNotifySyncData(): ByteArray {
        val byteArray = byteArrayOf(0x17, CMD_WRITE.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 启动/停止Live直播
     */
    fun setLiveSwitch(switch: Int, liveTime: Long): ByteArray {
        var byteArray = byteArrayOf(0x06, CMD_WRITE.toByte(), switch.toByte())
        byteArray = byteArray.plus(longTo2ByteArray(liveTime))
        return getCrc8Cmd(byteArray)
    }

    /**
     * 4.32 设置可连接WIFI热点 0x21
     * @param authType wifi认证类型
     */
    fun setConnectWiFi(wifiMac: String, wifiPassword: String, authType: Int): ByteArray {
        //20字节一个包，分包发送,前面4个字节为固定包头，后面16个字节为包的内容
        val totalPackage = 12 + wifiPassword.length - 4
        val packageNum = (totalPackage / 16) + 1
        var byteArray = byteArrayOf(0x21, CMD_WRITE.toByte(), packageNum.toByte(), 0x01)
        byteArray = byteArray.plus(macToByte(wifiMac))
        byteArray = byteArray.plus(authType.toByte())
        byteArray = byteArray.plus(wifiPassword.length.toByte())
        if (!TextUtils.isEmpty(wifiPassword)) {
            val passwordCharArray = wifiPassword.toCharArray()
            for (pca in passwordCharArray) {
                val b = pca.code.toByte()
                byteArray = byteArray.plus(b)
            }
        }
        return getCrc8Cmd(byteArray)
    }

    /**
     * 恢复出厂设置
     */
    fun factoryReset(): ByteArray {
        val byteArray = byteArrayOf(0x19, CMD_WRITE.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 设置设备工作状态
     */
    fun setWorkingStatus(writeAndRed: Int = CMD_WRITE, status: Int = 3): ByteArray {
        val byteArray = byteArrayOf(0x1A, writeAndRed.toByte(), status.toByte())
        return getCrc8Cmd(byteArray)
    }

    /**
     * 围栏设置
     */
    fun setFences(fencesBean: FencesBean): ByteArray {
        var byteArray = byteArrayOf(0x13, CMD_WRITE.toByte())
        fencesBean.apply {
            val fenceIdByteArray = hexStringToByteArray(fenceId.takeLast(8))
            byteArray = byteArray.plus(fenceIdByteArray)
            byteArray = byteArray.plus(
                byteArrayOf(
                    isOn.toByte(), fenceType.toByte(), fenceShapeType.toByte()
                )
            )
            if (fenceShapeType == ConstantInt.Type1) {
                byteArray = byteArray.plus(longTo4ByteArray((longitudeCenter * 1000000L).toLong()))
                byteArray = byteArray.plus(longTo4ByteArray((latitudeCenter * 1000000L).toLong()))
                byteArray = byteArray.plus(longTo4ByteArray((radius.toLong())))
            } else {
                byteArray = byteArray.plus(longTo4ByteArray((longitudeA * 1000000L).toLong()))
                byteArray = byteArray.plus(longTo4ByteArray((latitudeA * 1000000L).toLong()))
                byteArray = byteArray.plus(longTo4ByteArray((longitudeB * 1000000L).toLong()))
            }
            byteArray = byteArray.plus(longTo4ByteArray((latitudeB * 1000000L).toLong()))
            byteArray = byteArray.plus(longTo4ByteArray((longitudeC * 1000000L).toLong()))
            byteArray = byteArray.plus(longTo4ByteArray((latitudeC * 1000000L).toLong()))
            byteArray = byteArray.plus(longTo4ByteArray((longitudeD * 1000000L).toLong()))
            byteArray = byteArray.plus(longTo4ByteArray((latitudeD * 1000000L).toLong()))
            byteArray = byteArray.plus(longTo4ByteArray((longitudeE * 1000000L).toLong()))
            byteArray = byteArray.plus(longTo4ByteArray((latitudeE * 1000000L).toLong()))
            byteArray = byteArray.plus(longTo4ByteArray((longitudeF * 1000000L).toLong()))
            byteArray = byteArray.plus(longTo4ByteArray((latitudeF * 1000000L).toLong()))
        }
        return getCrc8Cmd(byteArray)
    }

    /**
     * 查询围栏
     */
    fun getFences(): ByteArray {
        val byteArray = byteArrayOf(0x13, CMD_READ.toByte(), 0)
        return getCrc8Cmd(byteArray)
    }

    /**
     * 设置/查询定位时间间隔
     */
    fun setAndRedGpsDuration(writeAndRed: Int = CMD_WRITE, duration: Long = 0): ByteArray {
        var byteArray = byteArrayOf(0x12, writeAndRed.toByte())
        byteArray = byteArray.plus(longTo2ByteArray(duration))
        return getCrc8Cmd(byteArray)
    }

    fun getPhoneLocation(lat: Double, lon: Double): ByteArray {
        var byteArray = byteArrayOf(0x23, CMD_READ.toByte(), 0)
        byteArray = byteArray.plus(longTo4ByteArray((lon * 1000000).toLong()))
        byteArray = byteArray.plus(longTo4ByteArray((lat * 1000000).toLong()))
        return getCrc8Cmd(byteArray)
    }

    fun setProxy(result: Int, data: ByteArray?): ByteArray {
        if (null == data) {
            return getCrc8Cmd(byteArrayOf(0x24, result.toByte(), 0))
        } else {
            var byteArray = byteArrayOf(0x24, result.toByte(), data.size.toByte())
            byteArray = byteArray.plus(data)
            return getCrc8Cmd(byteArray)
        }
    }
}

