package com.dlc.eboard.ui

import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.*
import android.view.View
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import cn.bingoogolapple.qrcode.core.BGAQRCodeUtil
import cn.bingoogolapple.qrcode.zxing.QRCodeEncoder
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.dlc.eboard.LabApp
import com.dlc.eboard.R
import com.dlc.eboard.common.CommonUtils
import com.dlc.eboard.common.SensorEnum
import com.dlc.eboard.common.SignType
import com.dlc.eboard.databinding.ActivityMainBinding
import com.dlc.eboard.event.OnlineUserEvent
import com.dlc.eboard.mqtt.AudioService
import com.dlc.eboard.mqtt.entity.BulletinBoardEntity
import com.dlc.eboard.mqtt.event.*
import com.dlc.eboard.serial.OnSerialScanListener
import com.dlc.eboard.serial.SerialPortHelper
import com.dlc.eboard.sp.DeviceSp
import com.dlc.eboard.ui.common.BaseCountDownActivity
import com.dlc.eboard.ui.dialog.*
import com.dlc.eboard.ui.lib.LabDetailActivity
import com.dlc.eboard.ui.monitor.MonitorListActivity
import com.dlc.eboard.ui.msds.InstructionActivity
import com.dlc.eboard.ui.leave.LeaveActivity
import com.dlc.eboard.ui.person.LaboratoryPersonActivity
import com.dlc.eboard.ui.risk.RiskActivity
import com.dlc.eboard.ui.rule.SafetyRegulationActivity
import com.dlc.eboard.ui.settings.PasswordDialog
import com.dlc.eboard.ui.settings.SettingsActivity
import com.dlc.eboard.ui.things.ThingsActivity
import com.dlc.eboard.ui.sign.SignInActivity
import com.dlc.eboard.ui.widget.HomeSensorView
import com.dlc.eboard.ui.widget.LooperLayoutManager
import com.dlc.eboard.ui.widget.NavViewCompat
import com.dlc.eboard.ui.widget.TitleBar
import com.rc.core.log.RcLog
import com.rc.core.ui.widget.decoration.NoLastLineItemDecoration
import com.rc.core.util.DeviceUtils
import com.rc.core.util.FastClickDelegate
import com.rc.core.util.ifNullOrEmpty
import com.rc.httpcore.client.ApiRepository
import com.rc.httpcore.exception.NetException
import com.rc.httpcore.vo.request.CommonSignInReq
import com.rc.httpcore.vo.response.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.lang.Exception
import java.util.*
import kotlin.collections.HashMap
import kotlin.collections.HashSet

/**
 * 首页
 *
 * @author ReiChin_
 */
class MainActivity : BaseCountDownActivity<ActivityMainBinding>() {

    companion object {
        // 文化图15s -> 整改信息30s -> 消息通知15s
        private const val BANNER_TIME_WORKBENCH = 15 * 1000L // 文化图15s
        private const val BANNER_TIME_REFORM_INFO = 30 * 1000L // 整改信息30s
        private const val BANNER_TIME_NOTICE_INFO = 15 * 1000L // 消息通知15s

        private const val WHAT_WORKBENCH = 1 // 实验室文化图
        private const val WHAT_REFORM_INFO = 2 // 整改信息
        private const val WHAT_NOTICE_INFO = 3 // 消息通知

        private const val LOAD_NET_WORKBENCH = true // 是否从网络上加载实验室文化图

        private const val SENSOR_SPLASH_TIME = 3000L // 传感器面板1.5s自动滚动
    }

    override fun createViewBinding() = ActivityMainBinding.inflate(layoutInflater)

    override val mTitleBar: TitleBar by lazy { viewBinding.titleBar }
    override val mNavView: NavViewCompat? = null

    private val mBulletinBoardAdapter = MainBoardAdapter()

    private val mCheckMachineMsgAdapter = CheckMachineMsgAdapter()
    private var mCheckMachineList: List<CheckMachineVo>? = null

    private var mBannerImageData: List<BannerImageBean>? = null

    private var mNoticeList: List<ContentMachineVo>? = null

    private val mSerialPortHelper by lazy {
        SerialPortHelper(this, object : OnSerialScanListener {
            override fun onServiceConnected() {
                if ("1" == LabApp.sLabConfig?.isRelationGuard) {
                    // 有门禁，登录成功后自动开门
                    RcLog.info("MainActivity# auto open door")
                    handleOpenDoor()
                }
            }
        })
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        startService(Intent(this, HeartService::class.java))
        bindService(Intent(this, AudioService::class.java), mAudioConnection, BIND_AUTO_CREATE)
        mSerialPortHelper.bindService()

        // 实验室文化图 > 文化图
        val message = mBannerHandler.obtainMessage(WHAT_WORKBENCH)
        mBannerHandler.sendMessageDelayed(message, BANNER_TIME_WORKBENCH)
    }

    override fun onDestroy() {
        stopService(Intent(this, HeartService::class.java))
        unbindService(mAudioConnection)
        mSerialPortHelper.unbindService()
        mBannerHandler.removeCallbacksAndMessages(null)
        super.onDestroy()
    }

    private var mAudioBinder: AudioService.AudioBinder? = null

    private val mAudioConnection: ServiceConnection = object : ServiceConnection {

        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            mAudioBinder = service as AudioService.AudioBinder
        }

        override fun onServiceDisconnected(name: ComponentName) {
        }
    }

    private val mBannerHandler = object : Handler(Looper.getMainLooper()) {

        override fun handleMessage(msg: Message) {
            when (msg.what) {
                // 实验室文化图
                WHAT_WORKBENCH -> {
                    viewBinding.companyImg.visibility = View.VISIBLE
                    viewBinding.reformInfo.visibility = View.GONE
                    viewBinding.noticeInfo.visibility = View.GONE
                    if (LOAD_NET_WORKBENCH) {
                        // 显示文化图，并切换至下一张文化图
                        if (!mBannerImageData.isNullOrEmpty()) {
                            var index = msg.obj as? Int ?: 0
                            showImage(index)

                            index++
                            if (index < mBannerImageData!!.size) {
                                val message = obtainMessage(WHAT_WORKBENCH, index)
                                sendMessageDelayed(message, BANNER_TIME_WORKBENCH)
                                return
                            }
                        } else {
                            showDefaultImg()
                        }
                    }
                    val message = if (mCheckMachineList.isNullOrEmpty()) {
                        // 没有整改信息
                        if (mNoticeList.isNullOrEmpty()) {
                            // 没有消息通知，任然显示文化图
                            obtainMessage(WHAT_WORKBENCH)
                        } else {
                            // 有消息通知，显示消息通知
                            obtainMessage(WHAT_NOTICE_INFO)
                        }
                    } else {
                        // 有整改信息，显示整改信息
                        obtainMessage(WHAT_REFORM_INFO)
                    }
                    sendMessageDelayed(message, BANNER_TIME_WORKBENCH)
                }

                // 整改信息
                WHAT_REFORM_INFO -> {
                    if (mCheckMachineList.isNullOrEmpty()) {
                        // 没有整改信息
                        if (mNoticeList.isNullOrEmpty()) {
                            // 没有消息通知，任然显示文化图
                            obtainMessage(WHAT_WORKBENCH).sendToTarget()
                        } else {
                            // 有消息通知，显示消息通知
                            obtainMessage(WHAT_NOTICE_INFO).sendToTarget()
                        }
                        return
                    }
                    viewBinding.companyImg.visibility = View.GONE
                    viewBinding.reformInfo.visibility = View.VISIBLE
                    viewBinding.noticeInfo.visibility = View.GONE

                    val index = msg.obj as? Int ?: 0
                    val newlyData = when {
                        mCheckMachineList.isNullOrEmpty() -> null
                        index >= mCheckMachineList!!.size - 1 -> mCheckMachineList!!.last()
                        else -> mCheckMachineList!![index]
                    }
                    showReformInfo(newlyData)

                    if (mCheckMachineList.isNullOrEmpty()) {
                        // 没有整改信息
                        if (mNoticeList.isNullOrEmpty()) {
                            // 没有消息通知，任然显示文化图
                            obtainMessage(WHAT_WORKBENCH).sendToTarget()
                        } else {
                            // 有消息通知，显示消息通知
                            obtainMessage(WHAT_NOTICE_INFO).sendToTarget()
                        }
                        return
                    } else {
                        viewBinding.reformPage.visibility = View.VISIBLE
                        viewBinding.reformPage.text = "${index + 1}/${mCheckMachineList!!.size}"
                    }

                    if (mCheckMachineList.isNullOrEmpty()) {
                        // 没有整改信息
                        if (mNoticeList.isNullOrEmpty()) {
                            // 没有消息通知，任然显示文化图
                            obtainMessage(WHAT_WORKBENCH).sendToTarget()
                        } else {
                            // 有消息通知，显示消息通知
                            obtainMessage(WHAT_NOTICE_INFO).sendToTarget()
                        }
                    } else {
                        val message = if (index >= mCheckMachineList!!.size - 1) {
                            // 最后一条整改信息
                            if (mNoticeList.isNullOrEmpty()) {
                                // 没有消息通知，切换到显示文化图
                                obtainMessage(WHAT_WORKBENCH)
                            } else {
                                // 有消息通知，切换到消息通
                                obtainMessage(WHAT_NOTICE_INFO)
                            }
                        } else {
                            obtainMessage(WHAT_REFORM_INFO, index + 1)
                        }
                        sendMessageDelayed(message, BANNER_TIME_REFORM_INFO)
                    }
                }

                // 消息通知
                WHAT_NOTICE_INFO -> {
                    if (mNoticeList.isNullOrEmpty()) {
                        // 没有消息通知，显示文化图
                        obtainMessage(WHAT_WORKBENCH).sendToTarget()
                        return
                    }
                    viewBinding.companyImg.visibility = View.GONE
                    viewBinding.reformInfo.visibility = View.GONE
                    viewBinding.noticeInfo.visibility = View.VISIBLE

                    val index = msg.obj as? Int ?: 0
                    val newlyData = when {
                        mNoticeList.isNullOrEmpty() -> null
                        index >= mNoticeList!!.size - 1 -> mNoticeList!!.last()
                        else -> mNoticeList!![index]
                    }
                    showNoticeInfo(newlyData)
                    if (mNoticeList.isNullOrEmpty()) {
                        // 没有消息通知，显示文化图
                        obtainMessage(WHAT_WORKBENCH).sendToTarget()
                        return
                    } else {
                        viewBinding.noticePage.visibility = View.VISIBLE
                        viewBinding.noticePage.text = "${index + 1}/${mNoticeList!!.size}"
                    }

                    if (mNoticeList.isNullOrEmpty()) {
                        // 没有消息通知，显示文化图
                        obtainMessage(WHAT_WORKBENCH).sendToTarget()
                    } else {
                        val message = if (index >= mNoticeList!!.size - 1) {
                            // 最后一条整改信息
                            obtainMessage(WHAT_WORKBENCH)
                        } else {
                            obtainMessage(WHAT_NOTICE_INFO, index + 1)
                        }
                        sendMessageDelayed(message, BANNER_TIME_NOTICE_INFO)
                    }
                }
            }
        }
    }

    private fun showNoticeInfo(data: ContentMachineVo?) {
        // 显示通知信息：通知发布人，发布时间，通知内容
        viewBinding.issuePerson.text = data?.createBy
        viewBinding.issueTime.text = data?.createTime
        viewBinding.noticeContent.text = data?.contentMsg
    }

    @SuppressLint("SetTextI18n")
    private fun showReformInfo(data: CheckMachineVo?) {
        mCheckMachineMsgAdapter.setNewInstance(data?.detailList)
        viewBinding.nestedScrollView.fullScroll(View.FOCUS_UP)
        if (data?.details.isNullOrEmpty()) {
            mCheckMachineMsgAdapter.setEmptyView(R.layout.view_list_empty)
        }
        viewBinding.createTime.text = "检查时间：${data?.createTime ?: ""}"
        viewBinding.jcRyxm.text = "检查人：${data?.jcRyxm ?: ""}"
    }

    override fun initListener() {
        viewBinding.titleBar.setTitleInfoFromSp()
        viewBinding.titleBar.setOnLongClickListener {
            PasswordDialog(this) {
                val intent = Intent(this, SettingsActivity::class.java)
                startActivity(intent)
            }.show()
            true
        }
        // 信息牌
        viewBinding.labDetail.setOnClickListener(FastClickDelegate {
            val intent = Intent(this, LabDetailActivity::class.java)
            startActivity(intent)
        })
        // 视频监控
        viewBinding.monitor.setOnClickListener(FastClickDelegate {
            val intent = Intent(this, MonitorListActivity::class.java)
            startActivity(intent)
        })
        // 人员信息(老师)/实验人员(学生)
        viewBinding.labPerson.setOnClickListener(FastClickDelegate {
            val intent = Intent(this, LaboratoryPersonActivity::class.java)
            startActivity(intent)
        })
        // 规章制度
        viewBinding.safetyRegulation.setOnClickListener(FastClickDelegate {
            val intent = Intent(this, SafetyRegulationActivity::class.java)
            startActivity(intent)
        })
        // MSDS
        viewBinding.learnMaterial.setOnClickListener(FastClickDelegate {
            val intent = Intent(this, InstructionActivity::class.java)
            startActivity(intent)
        })
        // 危险源
        viewBinding.sourceOfRisk.setOnClickListener(FastClickDelegate {
            val intent = Intent(this, RiskActivity::class.java)
            startActivity(intent)
        })
        // 物联控制
        viewBinding.things.setOnClickListener(FastClickDelegate {
            val intent = Intent(this, ThingsActivity::class.java)
            startActivity(intent)
        })
        // 签到
        viewBinding.signIn.setOnClickListener(FastClickDelegate {
            if ("1" == LabApp.sUserVo?.pageType) {
                // 一类人员：巡查签到
                dispatchPatrolSign()
            } else {
                if ("1" == LabApp.sUserVo?.isDutyUser) {
                    // 值班人员：选择巡查签到/准入签到
                    PickSignTypeDialog(this) { type ->
                        if (SignType.PATROL.code == type) {
                            dispatchPatrolSign()
                        } else {
                            dispatchAccessSign()
                        }
                    }.show()
                } else {
                    // 其它人员：准入签到
                    dispatchAccessSign()
                }
            }
        })
        // 离开
        viewBinding.leave.setOnClickListener(FastClickDelegate {
            if ("1" == LabApp.sUserVo?.pageType) {
                // 一类人员：巡查签退
                callLeaveApi(SignType.PATROL)
            } else {
                if ("1" == LabApp.sUserVo?.isDutyUser) {
                    // 值班人员：选择巡查签退/准入签退
                    queryLeaveType {
                        // 准入签退
                        dispatchAccessLeave()
                    }
                } else {
                    // 其它人员：准入签退
                    dispatchAccessLeave()
                }
            }
        })
        // 开门
        viewBinding.openDoor.setOnClickListener(FastClickDelegate {
            RcLog.info("MainActivity# click openDoor view 门禁权限=${"1" == LabApp.sLabConfig?.isRelationGuard}")
            handleOpenDoor()
        })
        // 返回
        viewBinding.back.setOnClickListener(FastClickDelegate {
            logoutCountDownFinish()
        })

        viewBinding.bulletinBoardView.layoutManager = LooperLayoutManager(RecyclerView.HORIZONTAL)
        val decor = NoLastLineItemDecoration(this, DividerItemDecoration.HORIZONTAL)
        decor.setDrawable(ContextCompat.getDrawable(this, R.drawable.shape_item_divider_middle)!!)
        viewBinding.bulletinBoardView.addItemDecoration(decor)
        viewBinding.bulletinBoardView.adapter = mBulletinBoardAdapter

        viewBinding.reformRecyclerView.layoutManager = LinearLayoutManager(this)
        viewBinding.reformRecyclerView.isNestedScrollingEnabled = false
        viewBinding.reformRecyclerView.adapter = mCheckMachineMsgAdapter
    }

    private fun handleOpenDoor() {
        mSerialPortHelper.openDoor()
        SafetyCheckResultDialog(
            this,
            ResultEnum.SUCCESS,
            "开锁成功",
            3000
        ).apply {
            setCancelable(false)
            show()
        }
    }

    private fun dispatchAccessSign() {
        val param = CommonSignInReq().apply {
            labId = LabApp.sLabConfig?.labId
            userId = LabApp.sUserVo?.userId
        }
        if (false == mustAccessInCheck()) {
            // 直接签到
            callSignApi(SignType.ACCESS, param)
        } else {
            accessSignCheck(param) { result ->
                val intent = Intent(this, SignInActivity::class.java)
                intent.putExtra("sign_type", SignType.ACCESS.code)
                intent.putExtra("sign_face", result)
                startActivity(intent)
            }
        }
    }

    // 准入签到检测
    private fun accessSignCheck(param: CommonSignInReq, callback: (result: SignFaceVo) -> Unit) {
        showLoading()
        val disposable = ApiRepository.accessSignCheck(param)
            .subscribe({
                dismissLoading()
                callback.invoke(it)
            }, { throwable ->
                dismissLoading()
                if (!pretreatmentError(throwable, "签到核验")) {
                    throwable.printStackTrace()
                    showNetError(throwable)
                }
            })
        addDisposable(disposable)
    }

    private fun dispatchPatrolSign() {
        val param = CommonSignInReq().apply {
            num = CommonUtils.getAndroidId()
            labId = LabApp.sLabConfig?.labId
            userId = LabApp.sUserVo?.userId
        }
        if (false == mustPatrolAiCheck()) {
            // 直接签到
            callSignApi(SignType.PATROL, param)
        } else {
            patrolSignCheck(param) {
                val intent = Intent(this, SignInActivity::class.java)
                intent.putExtra("sign_type", SignType.PATROL.code)
                startActivity(intent)
            }
        }
    }

    // 巡查签到检测
    private fun patrolSignCheck(param: CommonSignInReq, callback: () -> Unit) {
        showLoading()
        val disposable = ApiRepository.patrolSignCheck(param)
            .subscribe({
                dismissLoading()
                callback.invoke()
            }, { throwable ->
                dismissLoading()
                if (!pretreatmentError(throwable, "签到核验")) {
                    throwable.printStackTrace()
                    showNetError(throwable)
                }
            })
        addDisposable(disposable)
    }

    private fun callSignApi(signType: SignType, param: CommonSignInReq) {
        showLoading("签到中...")
        val disposable = ApiRepository.commonSignIn(signType.code, param)
            .subscribe({
                dismissLoading()
                EventBus.getDefault().post(OnlineUserEvent())
                SafetyCheckResultDialog(
                    this,
                    ResultEnum.SUCCESS,
                    "签到成功",
                    3000
                ).show()
            }, { throwable ->
                dismissLoading()
                if (!pretreatmentError(throwable, "签到")) {
                    throwable.printStackTrace()
                    showNetError(throwable)
                }
            })
        addDisposable(disposable)
    }

    private fun pretreatmentError(throwable: Throwable, text: String): Boolean {
        if (throwable is NetException) {
            val message = throwable.message.ifNullOrEmpty("${text}失败，请联系实验室管理员。")
            //AudioPlayerManager.speakVoice(R.raw.audio_failed_sign_admin)
            SafetyCheckResultDialog(this, ResultEnum.FAIL, message, 3000).apply {
                setCancelable(false)
                show()
            }
            return true
        }
        return false
    }

    private fun dispatchAccessLeave() {
        if (false == mustAccessOutCheck()) {
            // 直接准入签退
            callLeaveApi(SignType.ACCESS)
        } else {
            accessLeaveCheck { resp ->
                val intent = Intent(this, LeaveActivity::class.java)
                intent.putExtra("data", resp)
                startActivity(intent)
            }
        }
    }

    private fun accessLeaveCheck(callback: (resp: SignInCheckResp) -> Unit) {
        if (null == LabApp.sLabConfig || null == LabApp.sUserVo) {
            showToast("暂无实验室信息，即将重新获取")
            CommonUtils.restartApp(this)
            return
        }

        showLoading()
        val disposable = ApiRepository.signOutCheck(true, LabApp.sLabConfig!!.labId, LabApp.sUserVo!!.userId)
            .subscribe({ data ->
                dismissLoading()
                if (data.state) {
                    callback.invoke(data)
                } else {
                    val message = if (data.message.isNullOrEmpty()) "核验失败，请联系管理员！" else data.message[0]
                    SafetyCheckResultDialog(this, ResultEnum.FAIL, message, 3000).apply {
                        setCancelable(false)
                        show()
                    }
                }
            }, { throwable ->
                dismissLoading()
                if (!pretreatmentError(throwable, "签退核验")) {
                    throwable.printStackTrace()
                    showNetError(throwable)
                }
            })
        addDisposable(disposable)
    }

    private fun queryLeaveType(callback: () -> Unit) {
        if (null == LabApp.sLabConfig || null == LabApp.sUserVo) {
            showToast("暂无实验室信息，即将重新获取")
            CommonUtils.restartApp(this)
            return
        }

        showLoading()
        val disposable = ApiRepository.isSignInType(LabApp.sLabConfig!!.labId, LabApp.sUserVo!!.userId)
            .subscribe({ patrol ->
                dismissLoading()
                if (patrol) {
                    callLeaveApi(SignType.PATROL)
                } else {
                    callback.invoke()
                }
            }, { throwable ->
                dismissLoading()
                if (!pretreatmentError(throwable, "签退")) {
                    throwable.printStackTrace()
                    showNetError(throwable)
                }
            })
        addDisposable(disposable)
    }

    private fun callLeaveApi(signType: SignType) {
        if (null == LabApp.sLabConfig || null == LabApp.sUserVo) {
            showToast("暂无实验室信息，即将重新获取")
            CommonUtils.restartApp(this)
            return
        }

        showLoading("签退中...")
        val disposable = ApiRepository.commonLeave(signType.code, LabApp.sLabConfig!!.labId, LabApp.sUserVo!!.userId)
            .subscribe({
                dismissLoading()
                EventBus.getDefault().post(OnlineUserEvent())
                SafetyCheckResultDialog(
                    this,
                    ResultEnum.SUCCESS,
                    "离开成功",
                    3000
                ).show()
            }, { throwable ->
                dismissLoading()
                if (!pretreatmentError(throwable, "离开")) {
                    throwable.printStackTrace()
                    showNetError(throwable)
                }
            })
        addDisposable(disposable)
    }

    // 是否配置了离开检查项
    private fun mustAccessOutCheck(): Boolean? {
        val laboratoryVo = DeviceSp.loadLaboratoryVo(this)
        if (null == laboratoryVo || null == LabApp.sLabConfig) {
            showToast("暂无实验室信息，即将重新获取")
            CommonUtils.restartApp(this)
            return null
        }
        return !laboratoryVo.outCheck.isNullOrEmpty()
    }

    // 是否需要准入AI检测
    private fun mustAccessInCheck(): Boolean? {
        val laboratoryVo = DeviceSp.loadLaboratoryVo(this)
        if (null == laboratoryVo || null == LabApp.sLabConfig) {
            showToast("暂无实验室信息，即将重新获取")
            CommonUtils.restartApp(this)
            return null
        }
        return !laboratoryVo.inCheck.isNullOrEmpty()
    }

    // 是否需要巡查AI检测
    private fun mustPatrolAiCheck(): Boolean? {
        val laboratoryVo = DeviceSp.loadLaboratoryVo(this)
        if (null == laboratoryVo || null == LabApp.sLabConfig) {
            showToast("暂无实验室信息，即将重新获取")
            CommonUtils.restartApp(this)
            return null
        }
        return !laboratoryVo.inspectInCheck.isNullOrEmpty()
    }

    override fun initData() {
        val laboratoryVo = DeviceSp.loadLaboratoryVo(this)
        if (null == laboratoryVo || null == LabApp.sLabConfig) {
            showToast("暂无实验室信息，即将重新获取")
            CommonUtils.restartApp(this)
            return
        }
        viewBinding.titleBar.setTitleInfoFromSp()

        initLaboratoryInfo(laboratoryVo)
        // 开门按钮显示控制
        if ("1" == LabApp.sLabConfig?.isRelationGuard) {
            viewBinding.openDoor.visibility = View.VISIBLE
            val drawable = ContextCompat.getDrawable(this, R.drawable.divider_transparent_main_right)
            viewBinding.rightContent.dividerDrawable = drawable
        } else {
            viewBinding.openDoor.visibility = View.GONE
            val drawable = ContextCompat.getDrawable(this, R.drawable.divider_transparent_main_right_v2)
            viewBinding.rightContent.dividerDrawable = drawable
        }
        // 视频监控按钮显示控制
        if ("1" == LabApp.sUserVo?.pageType) {
            viewBinding.monitorGroup.visibility = View.VISIBLE
        } else {
            viewBinding.monitorGroup.visibility = View.GONE
        }

        if (LOAD_NET_WORKBENCH) {
            queryBanner()
        }

        queryBulletinBoard()
        queryCheckMachineMsgList()
        queryNoticeMsgList()
    }

    private fun queryBanner() {
        val disposable = ApiRepository.bannerImages(CommonUtils.getAndroidId())
            .subscribe({
                preloadImage(it)
            }, {
                showDefaultImg()
            })
        addDisposable(disposable)
    }

    private val mBannerMap: MutableMap<Int, Boolean> = mutableMapOf()

    private fun preloadImage(data: List<BannerImageBean>?) {
        this.mBannerImageData = data
        this.mBannerMap.clear()
        if (data.isNullOrEmpty()) {
            showDefaultImg()
            return
        }
        data.forEachIndexed { index, item ->
            Glide.with(this)
                .load(item.imgUrl)
                .listener(object : RequestListener<Drawable> {
                    override fun onLoadFailed(
                        e: GlideException?,
                        model: Any?,
                        target: Target<Drawable>?,
                        isFirstResource: Boolean
                    ): Boolean {
                        mBannerMap[index] = false
                        showImage(0)
                        return false
                    }

                    override fun onResourceReady(
                        resource: Drawable?,
                        model: Any?,
                        target: Target<Drawable>?,
                        dataSource: DataSource?,
                        isFirstResource: Boolean
                    ): Boolean {
                        mBannerMap[index] = true
                        showImage(0)
                        return false
                    }
                })
                .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
                .preload()
        }
    }

    private fun showImage(index: Int) {
        if (mBannerImageData.isNullOrEmpty()
            || mBannerImageData!!.size != mBannerMap.size
        ) {
            showDefaultImg()
            return
        }

        val activeIndex = index % mBannerImageData!!.size
        if (true == mBannerMap[activeIndex]) {
            Glide.with(this)
                .load(mBannerImageData!![activeIndex].imgUrl)
                .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
                .into(viewBinding.companyImg)
        } else {
            showDefaultImg()
        }
    }

    private fun showDefaultImg() {
        viewBinding.companyImg.setImageResource(R.mipmap.img_sy_qywh)
    }

    private fun initLaboratoryInfo(laboratoryVo: LaboratoryVo) {
        val dangerColor = try {
            Color.parseColor(laboratoryVo.dangerColor)
        } catch (e: Exception) {
            Color.parseColor("#15CA48")
        }
        val bgDrawable = GradientDrawable()
        bgDrawable.cornerRadius = DeviceUtils.dip2px(this, 5.0f).toFloat()
        bgDrawable.setStroke(DeviceUtils.dip2px(this, 1.0f), dangerColor)

        viewBinding.labLevel.background = bgDrawable
        viewBinding.labLevel.setTextColor(dangerColor)
        viewBinding.labLevel.text =
            "${laboratoryVo.dangerName ?: ""}\n${laboratoryVo.dangerLevel ?: ""}"

        viewBinding.labName.text = laboratoryVo.address

        // 二维码
        GlobalScope.launch(Dispatchers.Main) {
            val bitmap = withContext(Dispatchers.IO) {
                QRCodeEncoder.syncEncodeQRCode(
                    laboratoryVo.qrCodeUrl,
                    BGAQRCodeUtil.dp2px(this@MainActivity, 150f)
                )
            }
            Glide.with(this@MainActivity)
                .asBitmap()
                .load(bitmap)
                .error(R.mipmap.img_error)
                .into(viewBinding.qrCode)
        }
    }

    private fun queryBulletinBoard() {
        showLoading("加载中...")
        val disposable = ApiRepository.functionList(LabApp.sLabConfig!!.labId)
            .subscribe({ data ->
                dismissLoading()
                mBulletinBoardAdapter.setNewInstance(data.toMutableList())
                viewBinding.bulletinBoardView.initTimer(4, data.size)
                viewBinding.bulletinBoardView.startAuto(SENSOR_SPLASH_TIME)
                if (data.isNullOrEmpty()) {
                    mBulletinBoardAdapter.setEmptyView(R.layout.view_list_empty)
                }

                queryWarning()
            }, { throwable ->
                dismissLoading()
                throwable.printStackTrace()
                showNetError(throwable)
                mBulletinBoardAdapter.setEmptyView(R.layout.view_list_empty)
            })
        addDisposable(disposable)
    }

    private fun queryWarning() {
        val disposable = ApiRepository.warnList(LabApp.sLabConfig!!.labId)
            .subscribe({ data ->
                mBulletinBoardAdapter.updateWaringValue(data)
            }, { throwable ->
                throwable.printStackTrace()
                showNetError(throwable)
            })
        addDisposable(disposable)
    }

    private fun queryCheckMachineMsgList() {
        val disposable = ApiRepository.checkMachineMsgList(LabApp.sLabConfig!!.labId)
            .subscribe({ response ->
                mCheckMachineList = response
                if (mCheckMachineList.isNullOrEmpty()) {
                    mCheckMachineMsgAdapter.setNewInstance(null)
                    mCheckMachineMsgAdapter.setEmptyView(R.layout.view_list_empty)
                    viewBinding.reformPage.visibility = View.GONE
                } else {
                    showReformInfo(mCheckMachineList!![0])
                    viewBinding.reformPage.visibility = View.VISIBLE
                    viewBinding.reformPage.text = "1/${mCheckMachineList!!.size}"
                }
            }, { throwable ->
                mCheckMachineList = null
                throwable.printStackTrace()
                showNetError(throwable)
                mCheckMachineMsgAdapter.setEmptyView(R.layout.view_list_empty)
                viewBinding.reformPage.visibility = View.GONE
            })
        addDisposable(disposable)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onCheckMachineEvent(event: CheckMachineEvent) {
        queryCheckMachineMsgList()
    }

    private fun queryNoticeMsgList() {
        val disposable = ApiRepository.contentMachineMsgList(LabApp.sLabConfig!!.labId)
            .subscribe({ response ->
                mNoticeList = response
                if (mNoticeList.isNullOrEmpty()) {
                    showNoticeInfo(null)
                    viewBinding.noticePage.visibility = View.GONE
                } else {
                    showNoticeInfo(mNoticeList!![0])
                    viewBinding.noticePage.visibility = View.VISIBLE
                    viewBinding.noticePage.text = "1/${mNoticeList!!.size}"
                }
            }, { throwable ->
                mNoticeList = null
                throwable.printStackTrace()
                showNetError(throwable)
                showNoticeInfo(null)
                viewBinding.noticePage.visibility = View.GONE
            })
        addDisposable(disposable)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onBannerEvent(event: BannerEvent) {
        if (LOAD_NET_WORKBENCH) {
            queryBanner()
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onBulletinBoardEvent(event: BulletinBoardEvent) {
        mBulletinBoardAdapter.updateSensorValue(event.data)
    }

    private var mWaringDialog: WaringDialog? = null

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onWarningEvent(event: WarningEvent) {
        if (null == mWaringDialog) {
            if (!event.data.isNullOrEmpty()) {
                mWaringDialog = WaringDialog(this, event.data).apply {
                    setOnDismissListener {
                        mWaringDialog = null
                    }
                }
                mWaringDialog!!.show()
            }
        } else {
            if (event.data.isNullOrEmpty()) {
                mWaringDialog!!.dismiss()
            } else {
                mWaringDialog!!.updateWaringValue(event.data)
            }
        }

        mBulletinBoardAdapter.updateWaringValue(event.data)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEmergencyEvent(event: EmergencyEvent) {
        when (event.type) {
            1 -> textParseVideo(event.data)
            2 -> mAudioBinder?.startPlayer(event.data)
        }
    }

    private fun textParseVideo(text: String?) {
        if (text.isNullOrEmpty()) return

        showLoading()
        val disposable = ApiRepository.textParseVideo(text)
            .subscribe({ data ->
                dismissLoading()
                mAudioBinder?.startPlayer(data.url)
            }, { throwable ->
                dismissLoading()
                throwable.printStackTrace()
                showNetError(throwable)
            })
        addDisposable(disposable)
    }

    override fun enabledLogoutCountDown() = true

}

class MainBoardAdapter :
    BaseQuickAdapter<LabBulletinBoardVo, BaseViewHolder>(R.layout.item_bulletin_board) {

    private val mValueMap = HashMap<String, BoardValue>()
    private val mWarningSet = HashSet<String>()

    private val mSensorMap = HashMap<String, SensorEnum>().apply {
        SensorEnum.values().forEach {
            put(it.funNum, it)
        }
    }

    private fun goneSensor(funNum: String?): Boolean {
        return SensorEnum.FIRE.funNum == funNum
    }

    override fun setNewInstance(list: MutableList<LabBulletinBoardVo>?) {
        val newlyList = list?.filter { !goneSensor(it.funNum) }

        if (null != newlyList) {
            mValueMap.clear()
            newlyList.forEach {
                mValueMap[it.funNum] = BoardValue(it.`val`, it.unit, it.formatVal)
            }
        }
        super.setNewInstance(newlyList?.toMutableList())
    }

    fun updateSensorValue(data: BulletinBoardEntity.Data?) {
        val newlyList = data?.functionStatuses?.filter { !goneSensor(it.funNum) }

        var valueChanged = mValueMap.size != newlyList?.size
        newlyList?.forEach { item ->
            val oldValue = mValueMap[item.funNum]
            if (!valueChanged) {
                valueChanged = oldValue?.value != item.`val` || oldValue?.unit != item.unit
            }
            mValueMap[item.funNum] = BoardValue(item.`val`, item.unit, item.formatVal)
        }

        if (valueChanged) {
            notifyDataSetChanged()
        }
    }

    fun updateWaringValue(data: List<LabBulletinBoardVo>?) {
        val newlyList = data?.filter { !goneSensor(it.funNum) }

        var valueChanged = mWarningSet.size != newlyList?.size
        if (!valueChanged) {
            val changedItem = newlyList?.find { !mWarningSet.contains(it.funNum) }
            valueChanged = null != changedItem
        }

        mWarningSet.clear()
        newlyList?.forEach { item ->
            mWarningSet.add(item.funNum)
        }

        if (valueChanged) {
            notifyDataSetChanged()
        }
    }

    override fun convert(holder: BaseViewHolder, item: LabBulletinBoardVo) {
        val itemView = holder.itemView as HomeSensorView
        itemView.setSensorInfo(
            item.describe,
            mSensorMap[item.funNum]?.icon ?: R.mipmap.icon_sy_wzcgq
        )
        val itemVal = mValueMap[item.funNum]
        itemView.setSensorValue(itemVal?.value, itemVal?.unit, mWarningSet.contains(item.funNum))
    }

    private data class BoardValue(val value: String?, val unit: String?, val formatVal: String?)

}

class CheckMachineMsgAdapter
    : BaseQuickAdapter<CheckMachineVo.Detail, BaseViewHolder>(R.layout.item_check_machine_msg) {

    override fun convert(holder: BaseViewHolder, item: CheckMachineVo.Detail) {
        holder.setText(R.id.number, "${holder.adapterPosition + 1}")
            .setText(R.id.yhMs, item.yhMs)
            .setText(R.id.optionCode, item.optionCode)
            .setText(R.id.zgjzTime, item.zgjzTime)
    }

}