package com.quyunshuo.module.home.service

import android.annotation.SuppressLint
import android.app.ActivityManager
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Environment
import android.os.Process
import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.amap.api.location.AMapLocationClient
import com.amap.api.location.AMapLocationClientOption
import com.amap.api.location.AMapLocationListener
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.hboxs.serialport.plc.util.HexUtils
import com.hboxs.serialport.plc.util.HexadecimalUtil
import com.hboxs.serialport.sbc.SBCHeartbeat
import com.hboxs.serialport.sbc.VBoxMessage
import com.hboxs.serialport.sbc.frame.VboxCommand
import com.hboxs.serialport.sbc.thread.ThreadGlobalParam
import com.hjq.http.EasyHttp
import com.hjq.http.listener.OnDownloadListener
import com.hjq.http.model.HttpMethod
import com.quyunshuo.androidbaseframemvvm.base.BaseApplication
import com.quyunshuo.androidbaseframemvvm.base.bean.Global
import com.quyunshuo.androidbaseframemvvm.base.utils.SpUtils
import com.quyunshuo.androidbaseframemvvm.common.bean.DataItem
import com.quyunshuo.androidbaseframemvvm.common.bean.LocalAlarmClockBean
import com.quyunshuo.androidbaseframemvvm.common.bean.VideoInfoBean
import com.quyunshuo.androidbaseframemvvm.common.constant.Heartbeat
import com.quyunshuo.androidbaseframemvvm.common.constant.MMKVName
import com.quyunshuo.androidbaseframemvvm.common.enums.AlarmClockEnum
import com.quyunshuo.androidbaseframemvvm.common.util.AlarmManagerUtil
import com.quyunshuo.androidbaseframemvvm.common.util.AlarmSettingUtil
import com.quyunshuo.androidbaseframemvvm.common.util.AppManager
import com.quyunshuo.androidbaseframemvvm.common.util.ByteUtils
import com.quyunshuo.androidbaseframemvvm.common.util.FileUtil
import com.quyunshuo.androidbaseframemvvm.common.util.LogUtil
import com.quyunshuo.androidbaseframemvvm.common.util.XLogUtil
import com.quyunshuo.module.home.activity.main.MainActivity
import com.quyunshuo.module.home.utils.CommodityManage
import com.quyunshuo.module.home.utils.DevStataUtlis
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.launch
import java.io.File
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import javax.inject.Inject


class GlobalServiceViewModel @Inject constructor(
    private val mRepo: GlobalServiceRepository,
) : LifecycleOwner {
    private val TAG = "GlobalServiceViewModel"
    lateinit var list: ArrayList<String>
    var downVideos: ArrayList<VideoInfoBean> = ArrayList()
    private val mLifecycleRegistry = LifecycleRegistry(this)
    override val lifecycle: Lifecycle
        get() = mLifecycleRegistry
    var threadGlobalParam: ThreadGlobalParam = ThreadGlobalParam()

    // 初始化完成。
    private val _initIsSuccess = MutableLiveData<Boolean>()
    val initIsSuccess: LiveData<Boolean> get() = _initIsSuccess


    //强制返回App的携程
    var forceBackToAppJob: Job? = null
    private val _error = MutableLiveData<String>()
    val error: LiveData<String> get() = _error

    private val _closeError = MutableLiveData<Boolean>()
    val closeError: LiveData<Boolean> get() = _closeError

    private val _showOrCloseLoading = MutableLiveData<Boolean>()
    val showOrCloseLoading: LiveData<Boolean> get() = _showOrCloseLoading
    private val _showStartupOrShutdown = MutableLiveData<Boolean>()//开关机
    val showStartupOrShutdown: LiveData<Boolean> get() = _showStartupOrShutdown
    private val _finshStartupOrShutdown = MutableLiveData<Boolean>()//完成开关机
    val finshStartupOrShutdown: LiveData<Boolean> get() = _finshStartupOrShutdown

    private val _aginstartInit = MutableLiveData<Boolean>()//完成开关机
    val aginstartInit: LiveData<Boolean> get() = _aginstartInit
    var machineInitialization = 1

    /**
     * 获取广告内容。
     */
    fun getVideoRule(ruleId: String = "775") {
        if (Heartbeat.managerId == "") {
            //没有连接服务器，那么就不没有必要执行。
            return
        }
        var sRuleId = ruleId
        if (ruleId == "1") {// 1换成 775
            sRuleId = "775"
        }
        CoroutineScope(Dispatchers.IO).launch {
            mRepo.getVideoRule(sRuleId).catch {
                LogUtil.d(TAG, "$ruleId:getVideoRule onerror: $it")
            }.collect {
                getVideoInfo(it)
                LogUtil.d(TAG, "$ruleId:getVideoRule onnext: $it")


            }
        }
    }

    fun getVideoInfo(videoIds: String) {
        val gson = Gson()
        list =
            gson.fromJson<ArrayList<String>>(videoIds, object : TypeToken<ArrayList<String?>?>() {
            }.type)
        //存储广告规则 ,用于前台播放。
        SpUtils.putString(MMKVName.PLAY_RULE, gson.toJson(list))
        //1. 根据id 获取广告信息。
        downVideos.clear()
        getvideo()
        //2. 获取的信息，通过一个map进行存储。
        //3. 获取完成后，进行广告的下载
        //4. 下载完成后，就可以了。
        //5. 是否有新的广告呢？如果规则一样，那么就没有必要了。如果不一样，则需要。
        //6. 可以播放的广告有哪些呢？根据广告规则。

    }

    fun getvideo() {
        val first = list.first()
        CoroutineScope(Dispatchers.IO).launch {
            mRepo.getVideoInfo(first).catch {
                LogUtil.d(TAG, "getVideoInfo error: $it")
            }.collect {
                //2. 获取的信息，通过一个map进行存储。
                val fromJson = Gson().fromJson(it, DataItem::class.java)
                val list1 =
                    Gson().fromJson<ArrayList<VideoInfoBean>>(
                        fromJson.data,
                        object : TypeToken<ArrayList<VideoInfoBean?>?>() {
                        }.type
                    )
                downVideos.add(list1[0])
                list.removeFirst()
                LogUtil.d(TAG, "getVideoInfo onnext: " + list1[0])
                if (list.isNotEmpty()) {
                    getvideo()
                } else {
                    //1 本地的所有广告数据
                    val allFiles = FileUtil.getAllFiles(
                        Environment.getExternalStorageDirectory().path + "/adB/",
                        ""
                    )
                    if (allFiles == null) {
                        return@collect
                    }
                    // 2 如果要下载的，本地已经有，则移除他的。
                    allFiles!!.forEach {
                        var removeId = -1
                        for ((index, videoInfoBean) in downVideos.withIndex()) {
                            if (it.name.split(".")[0] == videoInfoBean.id.toString()) {
                                removeId = index
                                break
                            }
                        }
                        if (removeId != -1) {
                            downVideos.removeAt(removeId)
                        }
                    }
                    LogUtil.d(TAG, "getvideo: " + downVideos.size)
                    if (downVideos.isNotEmpty()) {
                        //4. 获取完成后，进行广告的下载
                        downVideo()
                    }
                }
            }
        }
    }

    private fun downVideo() {
        val videoInfoBean = downVideos.first()
        val file = File(("/storage/emulated/0/adB" + "/"), videoInfoBean.id.toString() + ".mp4")
        LogUtil.d(TAG, "downVideo: " + downVideos[0].url)
        EasyHttp.download(this).method(HttpMethod.GET)
            .file(file)
            .url(videoInfoBean.url).listener(object : OnDownloadListener {
                override fun onDownloadStart(file: File) {
                    Heartbeat.adDownProgress = downVideos.size
                    LogUtil.d(TAG, "onDownloadStart: 开始下载$videoInfoBean")
                }

                override fun onDownloadProgressChange(file: File, progress: Int) {
                    Heartbeat.adDownProgress = progress
                    LogUtil.d(TAG, "onDownloadProgressChange: 下载中$progress")
                }

                override fun onDownloadSuccess(file: File) {
                    downVideos.removeFirst()
                    LogUtil.d(TAG, "onDownloadEnd: 下载成功$file" + ",待下载：${downVideos.size}")
                    Heartbeat.adDownProgress = downVideos.size
                    if (downVideos.isNotEmpty()) {
                        downVideo()
                    } else {
                        //todo 下载完了。干嘛呢？通知播放呗 Eventbus，可以重新播放。
                    }
                }

                override fun onDownloadFail(file: File?, e: Throwable?) {
                    LogUtil.d(TAG, "onDownloadFail下载失败:" + e?.message)
                }
            }).start()
    }

    fun getAlarmClock(type: String, number: Int, bootTimeNumber: Int, recursionNumber: Int) {
        CoroutineScope(Dispatchers.IO).launch {
            mRepo.getAlarmClock(type).catch {
                Log.d(TAG, "getAlarmClock catch: $it")
                val alarmClock = SpUtils.getString("AlarmClock$type", "")
                if (alarmClock!!.isNotEmpty()) {
                    val gson = Gson()
                    setAlarmClock(gson, alarmClock, type, number, bootTimeNumber)
                    return@catch
                }
                if (recursionNumber <= 2) {
                    getAlarmClock(type, number, bootTimeNumber, recursionNumber + 1)
                }


            }.collect {
                Log.d(TAG, "getAlarmClock: $it")
                if ("无闹钟数据" == it || "数据为空" == it) {
                    SpUtils.putString("AlarmClock$type", "");
                    return@collect
                }
                val gson = Gson()
                SpUtils.putString("AlarmClock$type", it);
                val i: Int = setAlarmClock(gson, it, type, number, bootTimeNumber)
                Log.d(TAG, "AlarmClock onNext: $i")

            }
        }
    }

    private fun setAlarmClock(
        gson: Gson,
        it: String,
        type: String,
        number: Int,
        bootTimeNumber: Int,
    ): Int {
        val alarmClock2: MutableMap<String, String>? =
            gson.fromJson<MutableMap<String, String>>(it, MutableMap::class.java) //数据
        val data: String = alarmClock2?.get("data").toString()
        Log.d(TAG, "AlarmClock2onNext:  $type----$alarmClock2")
        val arrayList: ArrayList<String>? =
            gson.fromJson<ArrayList<String>>(data, ArrayList::class.java)
        val i: Int = setAlarmClock(number, arrayList!!, type, bootTimeNumber)
        if (AlarmClockEnum.OPEN_DEV.code == type) {
            Heartbeat.bootTimeNumber = i
        } else if (AlarmClockEnum.CLOSE_DEV.code == type) {
            Heartbeat.offTimeNumber = i
        } else if (AlarmClockEnum.OPEN_SLEEP.code == type) {
            Heartbeat.openSleepNumber = i
        } else if (AlarmClockEnum.CLOSE_SLEEP.code == type) {
            Heartbeat.closeSleepNumber = i
        }
        return i
    }

    fun setAlarmClock(
        number: Int, weekTimes: java.util.ArrayList<String>, type: String,
        alarmNumber: Int,
    ): Int {
        var numberCount: Int = 0;
        Log.d(
            TAG,
            "AlarmClock2onNext alarmNumber:$alarmNumber;setAlarmClock: $number"
        )
        for (i in number until alarmNumber) { //清除所有的闹钟
            AlarmManagerUtil.cancelAlarm(BaseApplication.context, AlarmManagerUtil.ALARM_ACTION, i)
            Log.d(
                TAG,
                "AlarmClock2onNext alarmNumber:$alarmNumber;setAlarmClock: $i"
            )
        }
        for (weekTime: String in weekTimes) {
            val weekTimeArray = weekTime.split(",:".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray()
            val weeks = weekTimeArray[0].split(",".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray() //星期
            val times = weekTimeArray[1].split(":".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray() //时间
            var hour = ""
            var minute: String = ""
            var msg = ""
            if ("1" == type) { //只有关机的才需要。
                if (times[1].toInt() < 5) { //如果小于5，我们需要做好计算才行。00：00：00
                    //小于5，则
                    //  times[0]-1：
                    //  times[1]：4-5=-1,60-1=59,是正确的。
                    if (times[0].toInt() < 1) {
                        hour = (times[0].toInt() - 1 + 24).toString() + ""
                        Log.d(TAG, "setAlarmClock: 小于1")
                    } else {
                        hour = (times[0].toInt() - 1).toString() + ""
                        Log.d(TAG, "setAlarmClock: 大于1")
                    }
                    minute = (times[1].toInt() - 5 + 60).toString() + ""
                    Log.d(TAG, "setAlarmClock: 小于5")
                } else {
                    hour = times[0]
                    minute = (times[1].toInt() - 5).toString() + ""
                    Log.d(TAG, "setAlarmClock: 大于5")
                }
                val now = Calendar.getInstance()
                val sdf = SimpleDateFormat("HH:mm:ss")
                //设置时间
                val date1 = sdf.parse(
                    times[0] + ":" +
                            times[1] + ":" +
                            times[2]
                )
                Log.d(TAG, "setAlarmClock: $date1")
                //当前时间
                val date2 = sdf.parse(
                    (now[Calendar.HOUR_OF_DAY].toString() + ":" +
                            now[Calendar.MINUTE] + ":" +
                            now[Calendar.SECOND])
                )
                Log.d(TAG, "setAlarmClock: $date2")

                if (date1.compareTo(date2) > 0) {
                    Log.d(
                        TAG,
                        "Date1 时间在 Date2 之后"
                    ) //没过
                    val nowDate = date1.time //当前时间
                    val startDateTime = date2.time //真实时间
                    val diffSeconds = ((nowDate - startDateTime) / 1000).toInt()
                    Log.d(
                        TAG,
                        "setAlarmClock: $diffSeconds"
                    )
                    if (diffSeconds >= 360) {
                        times[0] = hour
                        times[1] = minute
                        msg = "show"
                        Log.d(
                            TAG, times[0] + "setAlarmClock: 弹窗" + times[1]
                        )
                    } else {
                        //不弹窗
                        Log.d(
                            TAG,
                            "Date1 时间在 Date2 之前"
                        ) //没过
                        Log.d(TAG, "setAlarmClock1: 不弹窗")
                    }
                } else { //过了
                    println("程序怎么会运行到这里?正常应该不会")
                    Log.d(TAG, "setAlarmClock1: 不弹窗")
                }
            }
            for (i in weeks.indices) {
                AlarmManagerUtil.setAlarm(
                    BaseApplication.context,
                    2,
                    times[0].toInt(),
                    times[1].toInt(),
                    times[2].toInt(),
                    i + number,
                    weeks[i].toInt(),
                    type + msg
                )
            }
            numberCount = number + weeks.size //累积。
        }
        Log.d(TAG, "setAlarmClock: $numberCount")
        return numberCount
    }

    fun getAlarmClock() {
        if (SpUtils.getBoolean(MMKVName.ALARMCLOCK_TYPE, false)!!) {
            //本地闹钟
            val productStr = SpUtils.getString(
                MMKVName.LOCAL_ALARM_CLOCK,
                Gson().toJson(ArrayList<LocalAlarmClockBean>())
            )
            var list: ArrayList<LocalAlarmClockBean>? = null
            list = Gson().fromJson(
                productStr,
                object : TypeToken<ArrayList<LocalAlarmClockBean?>?>() {}.type
            )
            if (list!!.isEmpty()) {
                return
            }
            AlarmSettingUtil.setAlarmClock(list)
        } else {
            getAlarmClock(AlarmClockEnum.OPEN_SLEEP.code, 400, Heartbeat.openSleepNumber, 1)
            getAlarmClock(AlarmClockEnum.CLOSE_SLEEP.code, 500, Heartbeat.closeSleepNumber, 1)
            getAlarmClock(AlarmClockEnum.CLOSE_DEV.code, 200, Heartbeat.offTimeNumber, 1)
            getAlarmClock(AlarmClockEnum.OPEN_DEV.code, 300, Heartbeat.bootTimeNumber, 1)
        }

    }

    fun sendBackData() {
        threadGlobalParam.startBackData()
    }

    fun startCloseError(isFatal: Boolean) {
        threadGlobalParam.startCloseError(isFatal)
    }

    fun startHeartbeat() {
        threadGlobalParam.startHeartbeat()
    }

    fun disposeData(messageEvent: VBoxMessage) {
        XLogUtil.d(messageEvent.cmd + ":messageEvent.data:" + messageEvent.data)
        when (messageEvent.cmd) {
            VboxCommand.CMD_INIT -> {
                // XLogUtil.d(messageEvent.cmd + ":messageEvent.data:" + messageEvent.data)
                Log.d("backinfo", "走进初始化" + messageEvent.data)
                cmdInit(messageEvent)
            }

            VboxCommand.CMD_HEARTBEAT -> {
                cmdHeartbeat(messageEvent)
            }

            VboxCommand.CMD_BACK_DATA -> {
                cmdBackData(messageEvent)
                threadGlobalParam.stopBackData()
            }

            VboxCommand.CMD_ERROR -> {
                cmdError(messageEvent)
            }

            VboxCommand.CMD_OPENORCLOSE -> {
                Log.d("backinfo", "收到开关机命令")
                threadGlobalParam.stopSetM3()
            }

            else -> {}
        }
    }


    /**
     * 处理 单片机 心跳数据
     */
    private fun cmdHeartbeat(messageEvent: VBoxMessage) {
        if (messageEvent.data.length < 112) {
            return
        }
        //机器状态码，设备目前处于关机的待机状态
        SBCHeartbeat.devCode = messageEvent.data.substring(106, 110)
        Log.d(TAG, "是否开机:" + SBCHeartbeat.isPowerOn)
        Log.d(TAG, "devCode:" + SBCHeartbeat.devCode)


        Global.commTime = System.currentTimeMillis()

        val overheatState = HexUtils.hexStr2BinStr(messageEvent.data.substring(0, 2))//温度超温状态
        Log.d(TAG, "overheatState:" + overheatState)
        val split = overheatState.trim().split("")
        // Log.d(TAG, "split:" + Gson().toJson(split))
        Log.d(
            //0100000
            TAG,
            overheatState + ":cmdHeartbeat: :" + split[0] + ":" + split[1] + ":" + split[2] + ":" + split[3]
        )
        //炉头温度:文档指针3表示炉头文档表达式为（3-2）*2 就是开始截取的位置，3-2的原因是5B 5B占了两个字节乘以2表示2个字符串为一个字节，而炉头温度是用一个字节表示，所以substring从2到4
        SBCHeartbeat.headTemp = ((split[1].toInt() * 256) + ByteUtils.hexStr2decimal(
            messageEvent.data.substring(
                2,
                4
            )
        )).toString()
        Log.d(TAG, "炉头温度: " + SBCHeartbeat.headTemp)
        //蒸汽温度
        SBCHeartbeat.steamTemp = ((split[2].toInt() * 256) + ByteUtils.hexStr2decimal(
            messageEvent.data.substring(
                4,
                6
            )
        )).toString()
        Log.d(TAG, "steamTemp: " + SBCHeartbeat.steamTemp)

        //热电偶温度3
        SBCHeartbeat.thermocoupleTemperature = ((split[3].toInt() * 256) + ByteUtils.hexStr2decimal(
            messageEvent.data.substring(
                6,
                8
            )
        )).toString()
        Log.d(TAG, "thermocoupleTemperature: " + SBCHeartbeat.thermocoupleTemperature)
        SBCHeartbeat.temperatureInsideTheCabinet =
            ByteUtils.hexStr2decimal(messageEvent.data.substring(12, 14)).toString()
        Log.d(TAG, "temperatureInsideTheCabinet: " + SBCHeartbeat.temperatureInsideTheCabinet)

        SBCHeartbeat.humidityInsideTheCabinet =
            ByteUtils.hexStr2decimal(messageEvent.data.substring(14, 16)).toString()
        Log.d(TAG, "humidityInsideTheCabinet: " + SBCHeartbeat.humidityInsideTheCabinet)


        SBCHeartbeat.outsideTemp =
            ByteUtils.hexStr2decimal(messageEvent.data.substring(16, 18)).toString()


        //柜外湿度
        SBCHeartbeat.outsideHumidity =
            ByteUtils.hexStr2decimal(messageEvent.data.substring(18, 20)).toString()

        Log.d(
            TAG,
            "cmdHeartbeat: " + SBCHeartbeat.headTemp + ":" + SBCHeartbeat.steamTemp + ":" + SBCHeartbeat.outsideTemp + ":" + SBCHeartbeat.outsideHumidity
        )
        SBCHeartbeat.fatalError = messageEvent.data.substring(90, 94)//
        SBCHeartbeat.nonFatalError = messageEvent.data.substring(94, 98)
        var loading = messageEvent.data.substring(80, 84)
        Log.d(
            "backinfo",
            "fatalError:${SBCHeartbeat.fatalError},nonFatalError:${SBCHeartbeat.nonFatalError}"
        )
        DevStataUtlis.fatalErrorOrnonFatalError(
            SBCHeartbeat.fatalError,
            SBCHeartbeat.nonFatalError,
            _error
        )
        DevStataUtlis.loadingDialog(loading, _showOrCloseLoading)
        DevStataUtlis.devOpenOrClose(
            SBCHeartbeat.devCode,
            threadGlobalParam,
            _showStartupOrShutdown,
            _finshStartupOrShutdown
        )

    }


    /**
     * 处理 单片机 初始化数据
     */
    private fun cmdInit(messageEvent: VBoxMessage) {
        //验证码是否正确。
        val sumHexPairs = HexUtils.sumHexPairs(messageEvent.data)
        if (sumHexPairs) {
            try {
                Log.d("backinfo", "数据长度：" + messageEvent.data.length)

                //   SBCHeartbeat.devCode = messageEvent.data.substring(0, 2)
                //是否保存设备数据了。
                SBCHeartbeat.saveDevData = messageEvent.data.substring(100, 102)
                Log.d("backinfo", "saveDevData:" + SBCHeartbeat.saveDevData)
                //机箱版本号
                SBCHeartbeat.crateVersion = "" + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        4,
                        6
                    )
                ) + "." + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        6,
                        8
                    )
                ) + "." + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        8,
                        10
                    )
                ) + "." + HexadecimalUtil.hex2dec(messageEvent.data.substring(10, 12))


                //机型
                SBCHeartbeat.devType = "" + ((HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        26,
                        28
                    )
                ) * 65536) + (HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        28,
                        30
                    )
                ) * 256) + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        30,
                        32
                    )
                ))
                Log.d("backinfo", "机型：" + SBCHeartbeat.devType)
                //设备铭牌号
                SBCHeartbeat.devDogtag = "" + (HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        32,
                        34
                    )
                ) * 65536) + (HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        34,
                        36
                    )
                ) * 256) + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        36,
                        38
                    )
                )
                Log.d("backinfo", "设备铭牌号：" + SBCHeartbeat.devDogtag)

                //机器定制版本
                SBCHeartbeat.devOType = "" + ((HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        44,
                        46
                    )
                ) * 256) + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        46,
                        48
                    )
                ))
                Log.d("backinfo", "设备操作类型：" + SBCHeartbeat.devOType)
                SBCHeartbeat.customizedVersion = "" + ((HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        48,
                        50
                    )
                ) * 256) + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        50,
                        52
                    )
                ))
                CommodityManage.getInstance()
                    .init(BaseApplication.context, "version_${SBCHeartbeat.customizedVersion}.json")
                Log.d(
                    "backinfo",
                    " SBCHeartbeat.customizedVersion:" + SBCHeartbeat.customizedVersion
                )

                //软件版本号
                SBCHeartbeat.softwareVersion = "" + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        12,
                        14
                    )
                ) + "." + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        14,
                        16
                    )
                ) + "." + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        16,
                        18
                    )
                ) + "." + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        18,
                        20
                    )
                )
                Log.d("backinfo", "软件版本号:" + SBCHeartbeat.softwareVersion)

                SBCHeartbeat.softDate = "" + ((HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        20,
                        22
                    )
                ) * 65536) + (HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        22,
                        24
                    )
                ) * 256) + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        24,
                        26
                    )
                ))
                Log.d("backinfo", "单片机软件日期:" + SBCHeartbeat.softDate)


                SBCHeartbeat.productionDate = "" + ((HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        38,
                        40
                    )
                ) * 65536) + (HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        40,
                        42
                    )
                ) * 256) + HexadecimalUtil.hex2dec(
                    messageEvent.data.substring(
                        42,
                        44
                    )
                ))
                _initIsSuccess.value = true
                threadGlobalParam.isActiveSbcInit = false
                SBCHeartbeat.initIsSuccess = true
                Log.d("softDate", "" + SBCHeartbeat.softDate)
            } catch (E: Exception) {
                Log.d("backinfo", "错误日志：" + E.message)
            }

        } else {
            _initIsSuccess.value = false
            SBCHeartbeat.initIsSuccess = false
        }
    }

    /**
     * 处理 单片机 后台数据
     */
    private fun cmdBackData(messageEvent: VBoxMessage) {
        XLogUtil.d("cmdBackData:" + messageEvent.data)
    }


    private fun cmdError(messageEvent: VBoxMessage) {

        if ("0000".equals(SBCHeartbeat.fatalError) || "0000".equals(SBCHeartbeat.nonFatalError)) {
            _closeError.value = true
            threadGlobalParam.stopCloseError()
        }
    }


    //高德地图
    //声明AMapLocationClient类对象
    var mLocationClient: AMapLocationClient? = null

    //声明AMapLocationClientOption对象
    var mLocationOption: AMapLocationClientOption? = null

    /**
     * 高德地图
     */
    fun aMap() {
        CoroutineScope(Dispatchers.IO).launch {

            AMapLocationClient.updatePrivacyShow(BaseApplication.context, true, true);
            AMapLocationClient.updatePrivacyAgree(BaseApplication.context, true);
            mLocationClient = AMapLocationClient(BaseApplication.context)
            //设置定位回调监听
            mLocationClient!!.setLocationListener(mLocationListener)
            mLocationOption = AMapLocationClientOption()
            if (Heartbeat.isForeign) {
                mLocationOption!!.setGeoLanguage(AMapLocationClientOption.GeoLanguage.EN)
            }
            /**
             * 设置定位场景，目前支持三种场景（签到、出行、运动，默认无场景）
             */
            /**
             * 设置定位场景，目前支持三种场景（签到、出行、运动，默认无场景）
             */
            /**
             * 设置定位场景，目前支持三种场景（签到、出行、运动，默认无场景）
             */
            /**
             * 设置定位场景，目前支持三种场景（签到、出行、运动，默认无场景）
             */
            mLocationOption!!.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.SignIn)
            //设置定位模式为AMapLocationMode.Hight_Accuracy，高精度模式。
            mLocationOption!!.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy)
            //设置定位间隔,单位毫秒,默认为2000ms，最低1000ms。
            mLocationOption!!.setGpsFirst(false) //可选，设置是否gps优先，只在高精度模式下有效。默认关闭
            mLocationOption!!.setHttpTimeOut(30000) //可选，设置网络请求超时时间。默认为30秒。在仅设备模式下无效

            //获取一次定位结果：
//该方法默认为false。
            mLocationOption!!.setOnceLocation(true)

            //获取最近3s内精度最高的一次定位结果：
//设置setOnceLocationLatest(boolean b)接口为true，启动定位时SDK会返回最近3s内精度最高的一次定位结果。如果设置其为true，setOnceLocation(boolean b)接口也会被设置为true，反之不会，默认为false。
            mLocationOption!!.setOnceLocationLatest(true)
            mLocationOption!!.setMockEnable(true)
            //                mLocationClient.setLocationOption(mLocationOption);
            //启动定位
//                mLocationClient.stopLocation();
            mLocationClient!!.startLocation()
            XLogUtil.d("aMapLocation：启动成功")
        }.start()
    }

    //声明定位回调监听器
    var mLocationListener: AMapLocationListener =
        AMapLocationListener { aMapLocation ->
            if (aMapLocation != null) {
                XLogUtil.d("aMapLocation:" + aMapLocation)
                if (aMapLocation.errorCode == 0) {
                    aMapLocation.locationType //获取当前定位结果来源，如网络定位结果，详见定位类型表
                    val latitude = aMapLocation.latitude //获取纬度
                    val longitude = aMapLocation.longitude //获取经度
                    Heartbeat.latitude = latitude
                    Heartbeat.longitude = longitude
                    aMapLocation.accuracy //获取精度信息
                    //aMapLocation.getAddress()
                    //                    aMapLocation.getAddress();//地址，如果option中设置isNeedAddress为false，则没有此结果，网络定位结果中会有地址信息，GPS定位不返回地址信息。
                    Heartbeat.address = aMapLocation.address
                    aMapLocation.country //国家信息
                    aMapLocation.province //省信息
                    aMapLocation.city //城市信息
                    aMapLocation.district //城区信息
                    aMapLocation.street //街道信息
                    aMapLocation.streetNum //街道门牌号信息
                    aMapLocation.cityCode //城市编码
                    aMapLocation.adCode //地区编码
                    aMapLocation.aoiName //获取当前定位点的AOI信息
                    aMapLocation.buildingId //获取当前室内定位的建筑物Id
                    aMapLocation.floor //获取当前室内定位的楼层
                    aMapLocation.gpsAccuracyStatus //获取GPS的当前状态
                    //获取定位时间
                    val df = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                    val date = Date(aMapLocation.time)
                    df.format(date)
                    mLocationClient!!.stopLocation()
                    //可在其中解析amapLocation获取相应内容。
                } else {
                    //定位失败时，可通过ErrCode（错误码）信息来确定失败的原因，errInfo是错误信息，详见错误码表。
                    Log.e(
                        "AmapError",
                        "location Error, ErrCode:" + aMapLocation.errorCode + ", errInfo:" + aMapLocation.errorInfo
                    )
                }
            }
        }

    /**
     * 强制跳回App
     */
    fun forceBackToApp() {
        if (forceBackToAppJob == null) {
            forceBackToAppJob = CoroutineScope(Dispatchers.IO).launch {
                while (true) {
                    delay(4000)
                    //判断程序是否在运行
                    val isRunning: Boolean = isServiceStarted(
                        BaseApplication.context,
                        "com.quyunshuo.androidbaseframemvvm"
                    )
                    XLogUtil.d("MyTestService,Build.MODEL onReceive:程序未开启============$isRunning")
                    //运行中，跳过他。
                    if (isRunning) {
                        continue
                    }
                    val intent: Intent = Intent(
                        BaseApplication.context,
                        MainActivity::class.java
                    ) //此处我是根据需要重新启动时先进入欢迎页
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) //关掉所要到的界面中间的activity

                    @SuppressLint("WrongConstant") val restartIntent = PendingIntent.getActivity(
                        BaseApplication.context, 0, intent,
                        Intent.FLAG_ACTIVITY_NEW_TASK or PendingIntent.FLAG_IMMUTABLE
                    )

                    //退出程序
                    val mgr =
                        BaseApplication.context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
                    mgr[AlarmManager.RTC, System.currentTimeMillis() + 1000] =
                        restartIntent // 1秒钟后重启应用，这个可以根据需要自己定义

                    //干掉当前的程序
                    LogUtil.d("MyTestService", "uncaughtException2: ")
                    Process.killProcess(Process.myPid())
                    System.exit(0)

                }

            }
        }

    }

    /**
     * 关掉强制跳回App
     */
    fun stopForceBackToApp() {
        forceBackToAppJob?.cancel()
        forceBackToAppJob = null
    }

    /**
     * 检测一个android程序是否在运行
     *
     * @param context
     * @param PackageName
     * @return
     */
    fun isServiceStarted(context: Context, packageName: String): Boolean {
        val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val runningProcesses = am.runningAppProcesses
        for (processInfo in runningProcesses) {
            if (processInfo.processName == packageName) {
                return true
            }
        }
        return false
    }

//    fun scheduleDailyAlarmWithWorkManager(context: Context) {
//        val constraints = Constraints.Builder()
//            .setRequiredNetworkType(NetworkType.CONNECTED) // 可选：设置网络要求
//            .build()
//
//        val dailyAlarmWorkRequest = PeriodicWorkRequestBuilder<AlarmWorker>(1, TimeUnit.DAYS)
//            .setConstraints(constraints)
//            .setInitialDelay(calculateInitialDelay(context), TimeUnit.MILLISECONDS)
//            .build()
//
//        WorkManager.getInstance(context)
//            .enqueueUniquePeriodicWork("DailyAlarmWork", ExistingPeriodicWorkPolicy.REPLACE, dailyAlarmWorkRequest)
//        XLogUtil.d("work manager执行了。")
//    }
//
//    // 计算首次执行前的延迟，确保任务在每天的 9 点执行
//    fun calculateInitialDelay(context: Context): Long {
//        val calendar = Calendar.getInstance().apply {
//            timeZone = TimeZone.getDefault()
//            set(Calendar.HOUR_OF_DAY, 14)
//            set(Calendar.MINUTE, 46)
//            set(Calendar.SECOND, 0)
//            set(Calendar.MILLISECOND, 0)
//        }
//
//        val currentTime = System.currentTimeMillis()
//        val nextRunTime = calendar.timeInMillis
//
//        return if (currentTime > nextRunTime) {
//            // 如果当前时间已经过了今天的 9 点，则设置到明天的 9 点
//            calendar.add(Calendar.DAY_OF_YEAR, 1)
//            calendar.timeInMillis - currentTime
//        } else {
//            nextRunTime - currentTime
//        }
//    }


    fun openOrClose(data: String) {
        threadGlobalParam.startSetM3(data)
    }
}