package com.grkj.iscs.view.activity.test.fingerprint

import android.Manifest
import android.graphics.Bitmap
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.util.Base64
import android.util.Log
import com.grkj.iscs.databinding.ActivityFingerPrintBinding
import com.grkj.iscs.util.log.LogUtil
import com.grkj.iscs.view.activity.test.fingerprint.ZKUSBManager.ZKUSBManager
import com.grkj.iscs.view.activity.test.fingerprint.ZKUSBManager.ZKUSBManagerListener
import com.grkj.iscs.view.base.BaseActivity
import com.zkteco.android.biometric.FingerprintExceptionListener
import com.zkteco.android.biometric.core.device.ParameterHelper
import com.zkteco.android.biometric.core.device.TransportType
import com.zkteco.android.biometric.core.utils.LogHelper
import com.zkteco.android.biometric.core.utils.ToolUtils
import com.zkteco.android.biometric.module.fingerprintreader.FingerprintCaptureListener
import com.zkteco.android.biometric.module.fingerprintreader.FingerprintSensor
import com.zkteco.android.biometric.module.fingerprintreader.FingprintFactory
import com.zkteco.android.biometric.module.fingerprintreader.ZKFingerService
import com.zkteco.android.biometric.module.fingerprintreader.exception.FingerprintException

class FingerPrintActivity : BaseActivity<ActivityFingerPrintBinding>() {

    companion object {
        private const val REQUEST_PERMISSION_CODE = 9
        private const val ZKTECO_VID: Int = 0x1b55
        private const val LIVE20R_PID: Int = 0x0120
        private const val LIVE10R_PID: Int = 0x0124
        private const val ENROLL_COUNT: Int = 3
    }

    private var bStarted = false
    private var usb_pid = 0
    private var zkusbManager: ZKUSBManager? = null
    private val usb_vid: Int = ZKTECO_VID
    private var fingerprintSensor: FingerprintSensor? = null
    private var bRegister = false
    private var enroll_index = 0
    private var isReseted = false
    private val deviceIndex = 0
    private val regtemparray = Array(3) {
        ByteArray(
            2048
        )
    }
//    private val dbManager: DBManager = DBManager()
    private val strUid: String? = null
//    private var dbFileName: String? = null


    override val viewBinding: ActivityFingerPrintBinding
        get() = ActivityFingerPrintBinding.inflate(layoutInflater)

    override fun initView() {
//        dbFileName = filesDir.absolutePath + "/zkfinger10.db"
        checkStoragePermission()
        zkusbManager = ZKUSBManager(this.applicationContext, zkusbManagerListener)
        zkusbManager?.registerUSBPermissionReceiver()
        
        mBinding?.start?.setOnClickListener {
            if (bStarted) {
                mBinding?.txtResult?.setText("Device already connected!")
                return@setOnClickListener
            }
            if (!enumSensor()) {
                mBinding?.txtResult?.setText("Device not found!")
                return@setOnClickListener
            }
            tryGetUSBPermission()
        }

        mBinding?.stop?.setOnClickListener {

        }
        
        mBinding?.register?.setOnClickListener {

        }
        
        mBinding?.identify?.setOnClickListener {

        }
        
        
        mBinding?.delete?.setOnClickListener {

        }
        
        mBinding?.clear?.setOnClickListener {

        }

        mBinding?.exit?.setOnClickListener {
            finish()
        }
    }

    private fun checkStoragePermission() {
        val permission = arrayOf(
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
        )
        val deniedPermissions: ArrayList<String> = PermissionUtils.checkPermissions(
            this, permission
        )
        if (deniedPermissions.isEmpty()) {
            //permission all granted
            LogUtil.i("[checkStoragePermission]: all granted")
        } else {
            val size = deniedPermissions.size
            val deniedPermissionArray = deniedPermissions.toTypedArray<String>()
            PermissionUtils.requestPermission(this, deniedPermissionArray, REQUEST_PERMISSION_CODE)
        }
    }

    private fun afterGetUsbPermission() {
        openDevice()
    }

    private fun tryGetUSBPermission() {
        zkusbManager?.initUSBPermission(usb_vid, usb_pid)
    }


    private val fingerprintCaptureListener: FingerprintCaptureListener =
        object : FingerprintCaptureListener {
            override fun captureOK(fpImage: ByteArray?) {
                val bitmap: Bitmap = ToolUtils.renderCroppedGreyScaleBitmap(
                    fpImage,
                    fingerprintSensor?.getImageWidth()!!,
                    fingerprintSensor?.getImageHeight()!!
                )
                runOnUiThread { mBinding?.imageFP?.setImageBitmap(bitmap) }
            }

            override fun captureError(e: FingerprintException?) {
                // nothing to do
            }

            override fun extractOK(fpTemplate: ByteArray?) {
                if (bRegister) {
                    doRegister(fpTemplate)
                } else {
                    doIdentify(fpTemplate)
                }
            }

            override fun extractError(i: Int) {
                // nothing to do
            }
        }

    private val fingerprintExceptionListener: FingerprintExceptionListener =
        object : FingerprintExceptionListener {
            override fun onDeviceException() {
                LogUtil.e("usb exception!!!")
                if (!isReseted) {
                    try {
                        fingerprintSensor?.openAndReboot(deviceIndex)
                    } catch (e: FingerprintException) {
                        e.printStackTrace()
                    }
                    isReseted = true
                }
            }
        }

    private val zkusbManagerListener: ZKUSBManagerListener = object : ZKUSBManagerListener {
        override fun onCheckPermission(result: Int) {
            afterGetUsbPermission()
        }

        override fun onUSBArrived(device: UsbDevice?) {
            if (bStarted) {
                closeDevice()
                tryGetUSBPermission()
            }
        }

        override fun onUSBRemoved(device: UsbDevice?) {
            LogUtil.d("usb removed!")
        }
    }

    private fun openDevice() {
        createFingerprintSensor()
        bRegister = false
        enroll_index = 0
        isReseted = false
        try {
            //fingerprintSensor?.setCaptureMode(1);
            fingerprintSensor?.open(deviceIndex)
            //load all templates form db
//            if (dbManager.opendb(dbFileName) && dbManager.getCount() > 0) {
//                val vUserList: HashMap<String, String> = dbManager.queryUserList()
//                var ret = 0
//                if (vUserList.size > 0) {
//                    for ((strID, strFeature) in vUserList) {
//                        val blobFeature = Base64.decode(strFeature, Base64.NO_WRAP)
//                        ret = ZKFingerService.save(blobFeature, strID)
//                        if (0 != ret) {
//                            LogUtil.e("add [$strID] template failed, ret=$ret")
//                        }
//                    }
//                }
//            }
            run {
                // device parameter
                LogUtil.d("sdk version" + fingerprintSensor?.getSDK_Version())
                LogUtil.d("firmware version" + fingerprintSensor?.getFirmwareVersion())
                LogUtil.d("serial:" + fingerprintSensor?.getStrSerialNumber())
                LogUtil.d("width=" + fingerprintSensor?.getImageWidth() + ", height=" + fingerprintSensor?.getImageHeight())
            }
            fingerprintSensor?.setFingerprintCaptureListener(deviceIndex, fingerprintCaptureListener)
            fingerprintSensor?.SetFingerprintExceptionListener(fingerprintExceptionListener)
            fingerprintSensor?.startCapture(deviceIndex)
            bStarted = true
            mBinding?.txtResult?.setText("connect success!")
        } catch (e: FingerprintException) {
            e.printStackTrace()
            // try to  reboot the sensor
            try {
                fingerprintSensor?.openAndReboot(deviceIndex)
            } catch (ex: FingerprintException) {
                ex.printStackTrace()
            }
            mBinding?.txtResult?.setText("connect failed!")
        }
    }

    private fun closeDevice() {
        if (bStarted) {
            try {
                fingerprintSensor?.stopCapture(deviceIndex)
                fingerprintSensor?.close(deviceIndex)
            } catch (e: FingerprintException) {
                e.printStackTrace()
            }
            bStarted = false
        }
    }

    private fun enumSensor(): Boolean {
        val usbManager = this.getSystemService(USB_SERVICE) as UsbManager
        for (device in usbManager.deviceList.values) {
            val device_vid = device.vendorId
            val device_pid = device.productId
            if (device_vid == ZKTECO_VID && (device_pid == LIVE20R_PID || device_pid == LIVE10R_PID)) {
                usb_pid = device_pid
                return true
            }
        }
        return false
    }

    private fun createFingerprintSensor() {
        if (null != fingerprintSensor) {
            FingprintFactory.destroy(fingerprintSensor)
            fingerprintSensor = null
        }
        // Define output log level
        LogHelper.setLevel(Log.VERBOSE)
        LogHelper.setNDKLogLevel(Log.ASSERT)
        // Start fingerprint sensor
        val deviceParams = HashMap<String?, Any?>()
        //set vid
        deviceParams[ParameterHelper.PARAM_KEY_VID] = usb_vid
        //set pid
        deviceParams[ParameterHelper.PARAM_KEY_PID] = usb_pid
        fingerprintSensor = FingprintFactory.createFingerprintSensor(
            applicationContext,
            TransportType.USB,
            deviceParams
        )
    }

    fun doRegister(template: ByteArray?) {
        val bufids = ByteArray(256)
        var ret = ZKFingerService.identify(template, bufids, 70, 1)
        if (ret > 0) {
            val strRes = String(bufids).split("\t".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray()
            setResult("the finger already enroll by " + strRes[0] + ",cancel enroll")
            bRegister = false
            enroll_index = 0
            return
        }
        if (enroll_index > 0 && (ZKFingerService.verify(
                regtemparray.get(enroll_index - 1),
                template
            ).also {
                ret = it
            }) <= 0
        ) {
            setResult("please press the same finger 3 times for the enrollment, cancel enroll, socre=$ret")
            bRegister = false
            enroll_index = 0
            return
        }
        System.arraycopy(template, 0, regtemparray.get(enroll_index), 0, 2048)
        enroll_index++
        if (enroll_index == ENROLL_COUNT) {
            bRegister = false
            enroll_index = 0
            val regTemp = ByteArray(2048)
            if (0 < (ZKFingerService.merge(
                    regtemparray.get(0),
                    regtemparray.get(1),
                    regtemparray.get(2),
                    regTemp
                ).also {
                    ret = it
                })
            ) {
                var retVal = 0
                retVal = ZKFingerService.save(regTemp, strUid)
                if (0 == retVal) {
                    val strFeature = Base64.encodeToString(regTemp, 0, ret, Base64.NO_WRAP)
                    println("haha : $strFeature")
//                    dbManager.insertUser(strUid, strFeature)
                    setResult("enroll succ")
                } else {
                    setResult("enroll fail, add template fail, ret=$retVal")
                }
            } else {
                setResult("enroll fail")
            }
            bRegister = false
        } else {
            setResult("You need to press the " + (3 - enroll_index) + " times fingerprint")
        }
    }

    private fun setResult(result: String) {
        val mStrText = result
        runOnUiThread { mBinding?.txtResult?.setText(mStrText) }
    }

    fun doIdentify(template: ByteArray?) {
        val bufids = ByteArray(256)
        val ret = ZKFingerService.identify(template, bufids, 70, 1)
        if (ret > 0) {
            val strRes = String(bufids).split("\t".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray()
            setResult("identify succ, userid:" + strRes[0].trim { it <= ' ' } + ", score:" + strRes[1].trim { it <= ' ' })
        } else {
            setResult("identify fail, ret=$ret")
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (bStarted) {
            closeDevice()
        }
        zkusbManager!!.unRegisterUSBPermissionReceiver()
    }
}