package com.dlc.laboratory.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.dlc.eboard.R
import com.dlc.eboard.common.CommonUtils
import com.dlc.eboard.databinding.ActivityLabMainBinding
import com.dlc.eboard.mqtt.AudioService
import com.dlc.eboard.mqtt.MqttService
import com.dlc.eboard.mqtt.event.*
import com.dlc.eboard.serial.SerialPortService
import com.dlc.eboard.sp.DeviceSp
import com.dlc.eboard.ui.CheckMachineMsgAdapter
import com.dlc.eboard.ui.HeartService
import com.dlc.eboard.ui.MainBoardAdapter
import com.dlc.eboard.ui.common.BaseCountDownActivity
import com.dlc.eboard.ui.dialog.WaringDialog
import com.dlc.eboard.ui.settings.PasswordDialog
import com.dlc.eboard.ui.settings.SettingsActivity
import com.dlc.eboard.ui.widget.LooperLayoutManager
import com.dlc.eboard.ui.widget.NavViewCompat
import com.dlc.eboard.ui.widget.TitleBar
import com.dlc.laboratory.ui.leave.ExLeaveActivity
import com.dlc.laboratory.ui.lib.ExLabDetailActivity
import com.dlc.laboratory.ui.msds.ExInstructionActivity
import com.dlc.laboratory.ui.person.ExLaboratoryPersonActivity
import com.dlc.laboratory.ui.risk.ExRiskActivity
import com.dlc.laboratory.ui.rule.ExSafetyRegulationActivity
import com.dlc.laboratory.ui.sign.ExSignInActivity
import com.dlc.laboratory.ui.things.SelectAuthMethodActivity
import com.rc.core.ui.widget.decoration.NoLastLineItemDecoration
import com.rc.core.util.DeviceUtils
import com.rc.httpcore.client.ApiRepository
import com.rc.httpcore.vo.response.BannerImageBean
import com.rc.httpcore.vo.response.CheckMachineVo
import com.rc.httpcore.vo.response.ContentMachineVo
import com.rc.httpcore.vo.response.LaboratoryVo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.lang.Exception

/**
 * info
 *
 * @author ReiChin_
 */
class LabMainActivity :
    BaseCountDownActivity<ActivityLabMainBinding>() {

    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() = ActivityLabMainBinding.inflate(layoutInflater)

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

    private var mLaboratoryVo: LaboratoryVo? = 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

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

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

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

    private val mConnection: ServiceConnection = object : ServiceConnection {

        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            service as MqttService.MqttBinder
            service.initMqtt(mLaboratoryVo!!.subId)
        }

        override fun onServiceDisconnected(name: ComponentName) {
        }
    }

    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.setOnLongClickListener {
            PasswordDialog(this) {
                val intent = Intent(this, SettingsActivity::class.java)
                startActivity(intent)
            }.show()
            true
        }
        // 信息牌
        viewBinding.labDetail.setOnClickListener {
            val intent = Intent(this, ExLabDetailActivity::class.java)
            startActivity(intent)
        }
        // 实验人员(学生)
        viewBinding.labPerson.setOnClickListener {
            val intent = Intent(this, ExLaboratoryPersonActivity::class.java)
            startActivity(intent)
        }
        // 规章制度
        viewBinding.safetyRegulation.setOnClickListener {
            val intent = Intent(this, ExSafetyRegulationActivity::class.java)
            startActivity(intent)
        }
        // MSDS
        viewBinding.learnMaterial.setOnClickListener {
            val intent = Intent(this, ExInstructionActivity::class.java)
            startActivity(intent)
        }
        // 危险源
        viewBinding.sourceOfRisk.setOnClickListener {
            val intent = Intent(this, ExRiskActivity::class.java)
            startActivity(intent)
        }
        // 物联控制
        viewBinding.things.setOnClickListener {
            val intent = Intent(this, SelectAuthMethodActivity::class.java)
            startActivity(intent)
        }
        // 签到
        viewBinding.signIn.setOnClickListener {
            val intent = Intent(this, ExSignInActivity::class.java)
            startActivity(intent)
        }
        // 离开
        viewBinding.leave.setOnClickListener {
            val intent = Intent(this, ExLeaveActivity::class.java)
            startActivity(intent)
        }

        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
    }

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

        initLaboratoryInfo()

        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()
        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() {
        val dangerColor = try {
            Color.parseColor(mLaboratoryVo?.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 =
            "${mLaboratoryVo?.dangerName ?: ""}\n${mLaboratoryVo?.dangerLevel ?: ""}"

        viewBinding.labName.text = mLaboratoryVo?.address

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

    private fun queryBulletinBoard() {
        showLoading("加载中...")
        val disposable = ApiRepository.functionList(mLaboratoryVo!!.subId)
            .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(mLaboratoryVo!!.subId)
            .subscribe({ data ->
                mBulletinBoardAdapter.updateWaringValue(data)
            }, { throwable ->
                throwable.printStackTrace()
                showNetError(throwable)
            })
        addDisposable(disposable)
    }

    private fun queryCheckMachineMsgList() {
        val disposable = ApiRepository.checkMachineMsgList(mLaboratoryVo!!.subId)
            .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(mLaboratoryVo!!.subId)
            .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)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onLabInfoEvent(event: LabInfoEvent) {
        showLoading("加载中...")
        val disposable = ApiRepository.laboratoryInfo(CommonUtils.getAndroidId())
            .subscribe({ data ->
                dismissLoading()
                DeviceSp.saveLaboratoryVo(this, data)
                mLaboratoryVo = data
                initLaboratoryInfo()
            }, { throwable ->
                dismissLoading()
                throwable.printStackTrace()
                showNetError(throwable)
            })
        addDisposable(disposable)
    }

}