package com.dlc.chemical.ui.common

import android.annotation.SuppressLint
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.KeyEvent
import android.view.View
import com.dlc.chemical.ChemicalApp
import com.dlc.chemical.R
import com.dlc.chemical.common.CommonUtils
import com.dlc.chemical.common.Constants
import com.dlc.chemical.databinding.ActivityTagScanBinding
import com.dlc.chemical.iflytek.AudioPlayerManager
import com.dlc.chemical.print.PrinterListener
import com.dlc.chemical.print.PrinterStateReceiver
import com.dlc.chemical.print.UsbPrinterManager
import com.dlc.chemical.serial.listener.OnSerialScanListener
import com.dlc.chemical.serial.port.scan.PortScanHelper
import com.dlc.chemical.ui.MainActivity
import com.dlc.chemical.ui.dialog.SimpleDialog
import com.dlc.chemical.ui.dialog.SimpleTipsDialog
import com.dlc.chemical.ui.dialog.SuccessDialog
import com.dlc.chemical.ui.dialog.TipsDialog
import com.dlc.chemical.ui.output.OutputErrorDialog
import com.dlc.chemical.ui.output.OutputStoreActivity
import com.dlc.chemical.ui.query.ChemicalsDetailActivity
import com.dlc.chemical.ui.revert.RevertActivity
import com.dlc.chemical.ui.use.UseActivity
import com.dlc.chemical.ui.use.UseVerifyFailDialog
import com.dlc.chemical.ui.use.UseWeightActivity
import com.dlc.chemical.ui.widget.TitleBar
import com.print.usbprint.util.USBUtil
import com.rc.core.log.RcLog
import com.rc.core.ui.ActivityCollector
import com.rc.httpcore.client.ApiRepository
import com.rc.httpcore.exception.NetException
import com.rc.httpcore.vo.request.OutputStockReq
import com.rc.httpcore.vo.request.TagCodeReq
import com.rc.httpcore.vo.request.UpdateRfidReq
import com.rc.httpcore.vo.response.CabinetLockVo
import com.rc.httpcore.vo.response.ChemicalBean
import com.rc.httpcore.vo.response.LockRespBean

/**
 * 标签（二维码、RFID）扫描
 *
 * @author ReiChin_
 */
class TagScanActivity : BaseCountDownActivity<ActivityTagScanBinding>(),
    TitleBar.TitleListener {

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

    private lateinit var mModuleEnum: ModuleEnum

    private var mChemicalId: String? = null

    override fun beforeSetContentView() {
        mModuleEnum = intent.getSerializableExtra("moduleEnum") as ModuleEnum
        mChemicalId = intent.getStringExtra("id")
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        mModuleEnum = intent?.getSerializableExtra("moduleEnum") as ModuleEnum
        mChemicalId = intent.getStringExtra("id")
        refreshUI()
    }

    @SuppressLint("SetTextI18n")
    override fun initViews(savedInstanceState: Bundle?) {

        viewBinding.titleBar.setTitleListener(this)
        viewBinding.titleBar.setTitleInfoFromSp()

        refreshUI()
    }

    private fun refreshUI() {
        if (ModuleEnum.INPUT_STORE == mModuleEnum
            || ModuleEnum.RFID == mModuleEnum
            || ModuleEnum.TAG_MANAGEMENT == mModuleEnum
        ) {
            viewBinding.tips.text = "请扫描RFID电子标签"
            AudioPlayerManager.speakVoice(R.raw.audio_swipe_rfid)
        } else {
            viewBinding.tips.text = "请扫描化学品二维码或RFID标签"
            AudioPlayerManager.speakVoice(R.raw.audio_swipe_qrcode_rfid)
        }

        viewBinding.moduleName.text = mModuleEnum.desc

        if (Constants.Mock.TEST_ENV) {
            Handler(Looper.getMainLooper()).postDelayed({
                if (ModuleEnum.USE == mModuleEnum) {
                    val chemicalBean = intent.getParcelableExtra("chemicalBean") as ChemicalBean?
                    handleScanEvent(OnSerialScanListener.ScanType.QRCode, chemicalBean?.tagCode ?: "")
                }
            }, 1500)
        }
    }

    /**
     * 查询已入库化学品
     */
    private fun queryChemicalByTagCodeForStock(rfidCode: String? = null, tagCode: String? = null) {
        if (isDestroyed) return
        val dialog = TipsDialog(this, -1)
        dialog.setCancelable(false)
        dialog.show()

        val param = TagCodeReq()
        param.tagCode = rfidCode ?: tagCode
        if (null == ChemicalApp.sLearnLoginVo && ModuleEnum.QUERY == mModuleEnum) {
            // 在未登录的情况下查询化学品
            param.machineCode = CommonUtils.getAndroidId()
        }
        // 在未登录的情况下查询化学品
        param.machineCode = CommonUtils.getAndroidId()
        param.qType = mModuleEnum.type
        val disposable = ApiRepository.queryByTagCode(param)
            .subscribe({ optional ->
                if (ModuleEnum.USE == mModuleEnum) {
                    val data = if (optional.isPresent) optional.get() else {
                        showToast("查无此标签")
                        return@subscribe
                    }
                    if (Constants.Mock.USE_FLOW_NEWLY) {
                        RcLog.info("TagScan>> oneUser:${intent.getStringExtra("oneUser")}, twoUser:${intent.getStringExtra("twoUser")}, lockLogId:${intent.getStringExtra("lockLogId")}")
                        val intent = Intent(this, UseWeightActivity::class.java)
                        intent.putExtra("chemicalBean", getIntent().getParcelableExtra("chemicalBean") as ChemicalBean?)
                        intent.putExtra("oneUser", getIntent().getStringExtra("oneUser"))
                        intent.putExtra("twoUser", getIntent().getStringExtra("twoUser"))
                        intent.putExtra("lockLogId", getIntent().getStringExtra("lockLogId"))
                        startActivity(intent)
                        finish()
                    } else {
                        val useBean: ChemicalBean? = intent.getParcelableExtra("chemicalBean")
                        if (null == useBean) {
                            val intent = Intent(this, UseActivity::class.java)
                            intent.putExtra("chemicalBean", data)
                            startActivity(intent)
                        } else {
                            val intent = Intent(this, UseWeightActivity::class.java)
                            intent.putExtra("chemicalBean", data)
                            intent.putExtra("oneUser", getIntent().getStringExtra("oneUser"))
                            intent.putExtra("twoUser", getIntent().getStringExtra("twoUser"))
                            startActivity(intent)
                            finish()
                        }
                    }
                    mHandleScanEvent = false
                } else if (ModuleEnum.OUTPUT_STORE == mModuleEnum) {
                    val data = if (optional.isPresent) optional.get() else {
                        showToast("查无此标签")
                        return@subscribe
                    }
                    val outputBean: ChemicalBean? = intent.getParcelableExtra("chemicalBean")
                    if (null == outputBean) {
                        val intent = Intent(this, OutputStoreActivity::class.java)
                        intent.putExtra("chemicalBean", data)
                        startActivity(intent)
                        mHandleScanEvent = false
                    } else {
                        // 调用出库api
                        callOutputApi(outputBean)
                    }
                } else if (ModuleEnum.QUERY == mModuleEnum) {
                    val data = if (optional.isPresent) optional.get() else {
                        showToast("查无此标签")
                        return@subscribe
                    }
                    // 进入化学品详情
                    val intent = Intent(this, ChemicalsDetailActivity::class.java)
                    intent.putExtra("chemicalBean", data)
                    startActivity(intent)
                    mHandleScanEvent = false
                } else if (ModuleEnum.INPUT_STORE == mModuleEnum) {
                    // 入库
                    dispatchInputSuccess(rfidCode!!)
                }
                dialog.dismiss()
            }, { throwable ->
                dialog.dismiss()
                showNetError(throwable)
                throwable.printStackTrace()
                mHandleScanEvent = false
            })
        addDisposable(disposable)
    }

    /**
     * 调用出库api
     *
     * @param stockStatus 库存状态 2-用结出库，3-作废出库
     */
    private fun callOutputApi(outputBean: ChemicalBean) {
        showLoading("保存中...")
        val param = OutputStockReq().apply {
            id = outputBean.id
            status = intent.getStringExtra("stockStatus")
            outOneUser = intent.getStringExtra("oneUser")
            outTwoUser = intent.getStringExtra("twoUser")
            lockLogId = intent.getStringExtra("lockLogId")
        }
        val disposable = ApiRepository.outStock(param)
            .subscribe({
                mHandleScanEvent = false
                dismissLoading()
                // 出库完成画面(继续出库)
                val intent = Intent(this, OutputStoreActivity::class.java)
                intent.putExtra("stockStatus", param.status)
                intent.putExtra("outputCompleted", true)
                startActivity(intent)
                finish()
            }, { throwable ->
                if (!pretreatmentOutputError(throwable, outputBean)) {
                    mHandleScanEvent = false
                    dismissLoading()
                    showNetError(throwable)
                    throwable.printStackTrace()
                }
            })
        addDisposable(disposable)
    }

    private fun pretreatmentOutputError(throwable: Throwable, outputBean: ChemicalBean): Boolean {
        if (throwable is NetException) {
            if ("500" == throwable.code
                && true == throwable.message?.contains("领用中")
            ) {
                dispatchOutputError_500(throwable.message, outputBean)
                return true
            }
        }
        return false
    }

    private fun queryByUserecord(chemicalId: String?, callback: (cBean: ChemicalBean) -> Unit) {
        showLoading("查询中...")
        val param = TagCodeReq()
        param.id = chemicalId
        val disposable = ApiRepository.queryByUserecord(param)
            .subscribe({ data ->
                dismissLoading()
                callback.invoke(data)
            }, { throwable ->
                dismissLoading()
                showNetError(throwable)
                throwable.printStackTrace()
            })
        addDisposable(disposable)
    }

    private fun dispatchOutputError_500(message: String?, outputBean: ChemicalBean) {
        if (null == message) return
        OutputErrorDialog(this, message, dialogListener = {
            queryByUserecord(outputBean.id) { cBean->
                val intent = Intent(this, RevertActivity::class.java)
                intent.putExtra("chemicalBean", cBean)
//                intent.putExtra("oneUser", getIntent().getStringExtra("oneUser"))
//                intent.putExtra("twoUser", getIntent().getStringExtra("twoUser"))
                startActivity(intent)
                ActivityCollector.removeActivity(2)
            }
        }).apply {
            setOnCancelListener {
                startActivity(Intent(this@TagScanActivity, MainActivity::class.java))
            }
        }.show()
    }

    private fun showUseVerifyFailDialog(useBean: ChemicalBean, scanTagCode: String?) {
        UseVerifyFailDialog(this, mModuleEnum, useBean, scanTagCode) { type ->
            if (UseVerifyFailDialog.TYPE_REOPEN_LOCK == type) {
                val lockType = when (mModuleEnum) {
                    ModuleEnum.USE -> LockType.USE.code
                    ModuleEnum.OUTPUT_STORE -> LockType.OUT_STOCK.code
                    else -> return@UseVerifyFailDialog
                }
                callOpenLockApi(lockType, useBean)
            }
            mHandleScanEvent = false
        }.show()
    }

    private fun callOpenLockApi(lockType: String, useBean: ChemicalBean) {
        showLoading("开锁中...")
        val param = CabinetLockVo()
        param.lockType = lockType
        param.joinId = useBean.joinId
        val disposable = ApiRepository.openLock(param)
            .subscribe({ data ->
                dismissLoading()
                if (data.success) {
                    // 开锁成功
                    dispatchOpenLockSuccess(param, data, useBean)
                } else {
                    showToast("开锁失败")
                }
            }, { throwable ->
                dismissLoading()
                showNetError(throwable)
                throwable.printStackTrace()
            })
        addDisposable(disposable)
    }

    private fun dispatchOpenLockSuccess(cabinetLock: CabinetLockVo, lockRespBean: LockRespBean, useBean: ChemicalBean) {
        AudioPlayerManager.speakVoice(R.raw.audio_success_open_lock)
        SuccessDialog(this, "开锁成功").apply {
            setCancelable(false)
            setOnDismissListener {
                val intent = Intent(this@TagScanActivity, ChemicalUnlockActivity::class.java)
                intent.putExtra("cabinetLock", cabinetLock)
                intent.putExtra("lockRespBean", lockRespBean)
                intent.putExtra("chemicalBean", useBean)
                if (ModuleEnum.OUTPUT_STORE == mModuleEnum) {
                    intent.putExtra("stockStatus", getIntent().getStringExtra("stockStatus"))
                }
                intent.putExtra("oneUser", getIntent().getStringExtra("oneUser"))
                intent.putExtra("twoUser", getIntent().getStringExtra("twoUser"))
                startActivity(intent)
                finish()
            }
        }.show()
    }

    private fun verifyChemicalBean(scanContent: String): Boolean {
        if (ModuleEnum.QUERY == mModuleEnum) return true

        val cBean: ChemicalBean = intent.getParcelableExtra("chemicalBean") ?: return true

        RcLog.info("verify cBean scanContent:${scanContent}, cBean.tagCode:${cBean.tagCode}, cBean.rfidCode:${cBean.rfidCode}")

        if (cBean.tagCode != scanContent && cBean.rfidCode != scanContent) {
            // 不一致
            showUseVerifyFailDialog(cBean, scanContent)
            return false
        }
        return true
    }

    /**
     * 归还时查询已领用化学品
     */
    private fun queryChemicalByTagCodeForUsed(rfidCode: String? = null, tagCode: String? = null) {
        if (isDestroyed) return
        val dialog = TipsDialog(this, -1)
        dialog.setCancelable(false)
        dialog.show()

        val param = TagCodeReq()
        param.tagCode = rfidCode ?: tagCode
        val disposable = ApiRepository.queryByUserecord(param)
            .subscribe({ data ->
                dialog.dismiss()
                if (ModuleEnum.REVERT == mModuleEnum) {
                    val intent = Intent(this, RevertActivity::class.java)
                    intent.putExtra("chemicalBean", data)
                    startActivity(intent)
                }
                mHandleScanEvent = false
            }, { throwable ->
                dialog.dismiss()
                showNetError(throwable)
                throwable.printStackTrace()
                mHandleScanEvent = false
            })
        addDisposable(disposable)
    }

    private fun dispatchChangeRFIDTagSuccess() {
        val message = "替换绑定成功！\n请将RFID标签粘在化学品瓶身上。"
        AudioPlayerManager.speakVoice(R.raw.audio_success_change_rfid)
        SimpleTipsDialog(this, message).apply {
            setOnDismissListener {
                finish()
                mHandleScanEvent = false
            }
        }.show()
    }

    private fun dispatchInputSuccess(rfidCode: String) {
        val intent = Intent()
        intent.putExtra("rfidCode", rfidCode)
        setResult(RESULT_OK, intent)
        finish()
        mHandleScanEvent = false
    }

    private fun showUpdateRfidTagDialog(rfidCode: String) {
        SimpleDialog(this,
            titleText = "本次更换标签编号：${rfidCode}",
            message = "确认更换？",
            messageTextColor = "#FF333333", dialogListener = {
                callUpdateRfidTagApi(rfidCode)
            }).apply {
            setOnCancelListener {
                mHandleScanEvent = false
            }
        }.show()
    }

    private fun callUpdateRfidTagApi(rfidCode: String) {
        showLoading("保存中...")
        val param = UpdateRfidReq()
        param.id = mChemicalId
        param.rfidCode = rfidCode
        val disposable = ApiRepository.updateStock(param)
            .subscribe({
                dismissLoading()
                dispatchChangeRFIDTagSuccess()
            }, { throwable ->
                dismissLoading()
                showNetError(throwable)
                throwable.printStackTrace()
                mHandleScanEvent = false
            })
        addDisposable(disposable)
    }

    private var mHandleScanEvent = false

    override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
        mPortScanHelper.dispatchKeyEvent(event)
        return super.dispatchKeyEvent(event)
    }

    private val mPortScanHelper by lazy {
        PortScanHelper(this, object : OnSerialScanListener {
            override fun dispatchScanEvent(type: OnSerialScanListener.ScanType, content: String) {
                if (!mHandleScanEvent) {
                    handleScanEvent(type, content)
                }
            }

        })
    }

    private fun handleScanEvent(type: OnSerialScanListener.ScanType, content: String) {
        mHandleScanEvent = true

        val rfidCode = if (OnSerialScanListener.ScanType.Rfid == type) content else null
        val tagCode = if (OnSerialScanListener.ScanType.QRCode == type) content else null

        when (mModuleEnum) {
            ModuleEnum.QUERY, // 查询化学品
            ModuleEnum.USE, // 领用化学品
            ModuleEnum.OUTPUT_STORE -> { // 化学品出库
                if (verifyChemicalBean(content)) {
                    queryChemicalByTagCodeForStock(rfidCode = rfidCode, tagCode = tagCode)
                }
            }
            ModuleEnum.REVERT -> { // 归还化学品
                queryChemicalByTagCodeForUsed(rfidCode = rfidCode, tagCode = tagCode)
            }

            ModuleEnum.INPUT_STORE -> { // 化学品入库
                if (OnSerialScanListener.ScanType.Rfid == type) {
                    queryChemicalByTagCodeForStock(rfidCode = rfidCode)
                } else {
                    mHandleScanEvent = false
                }
            }
            ModuleEnum.RFID -> { // RFID标签更换
                if (OnSerialScanListener.ScanType.Rfid == type) {
                    showUpdateRfidTagDialog(content)
                } else {
                    mHandleScanEvent = false
                }
            }
            ModuleEnum.TAG_MANAGEMENT -> { // 标签管理
                if (OnSerialScanListener.ScanType.Rfid == type) {
                    showPrintAirBottleLabelDialog(content)
                } else {
                    mHandleScanEvent = false
                }
            }
            else -> mHandleScanEvent = false
        }
    }

    private fun showPrintAirBottleLabelDialog(labelCode: String) {
        SimpleTipsDialog(
            context = this,
            message = "标签录入成功，请点击下方按钮打印二维码。",
            confirmText = "打印二维码",
            dialogListener = {
                val device = USBUtil.getInstance()
                    .getUsbDevice(
                        UsbPrinterManager.DEVICE_VID,
                        UsbPrinterManager.DEVICE_PID
                    )
                if (null != device && USBUtil.getInstance().IsOpen(device, this)) {
                    UsbPrinterManager.printAirBottleLabel(labelCode)
                } else {
                    showToast("未连接打印设备！")
                }
            }
        ).apply {
            setOnCancelListener {
                mHandleScanEvent = false
            }
        }.show()
    }

    private fun onPrinterEvent(success: Boolean, message: String) {
        if (success) {
            dispatchAirBottleLabelPrintSuccess()
        } else {
            mHandleScanEvent = false
            showToast(message)
        }
    }

    private fun dispatchAirBottleLabelPrintSuccess() {
        SimpleTipsDialog(
            context = this,
            message = "二维码打印成功，请将二维码粘贴至RFID标签上。",
            confirmText = "完成"
        ).apply {
            setOnDismissListener {
                mHandleScanEvent = false
            }
        }.show()
    }

    private var mPrinterStateReceiver: PrinterStateReceiver? = null

    private fun registerPrinterStateReceiver() {
        if (mPrinterStateReceiver == null) {
            val filter = IntentFilter()
            mPrinterStateReceiver = PrinterStateReceiver(printerListener = object : PrinterListener {
                override fun onPrintResult(success: Boolean, message: String) {
                    onPrinterEvent(success, message)
                }

            })
            filter.addAction(PrinterStateReceiver.ACTION_PRINTER_STATE)
            filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
            this.registerReceiver(mPrinterStateReceiver, filter)
        }
    }

    override fun onResume() {
        super.onResume()
        mPortScanHelper.onResume()

        registerPrinterStateReceiver()
    }

    override fun onPause() {
        mPortScanHelper.onPause()

        if (mPrinterStateReceiver != null) {
            unregisterReceiver(mPrinterStateReceiver)
            mPrinterStateReceiver = null
        }
        super.onPause()
    }

    override fun onHomeViewClicked(view: View) {
        startActivity(Intent(this, MainActivity::class.java))
    }

    override fun onBackViewClicked(view: View) {
        finish()
    }

}