package com.intergration.test

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.media.AudioManager
import android.media.CamcorderProfile
import android.os.Bundle
import android.os.Environment
import android.speech.tts.TextToSpeech
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.arcsoft.visdrive.sdk.ArcErrorInfo
import com.arcsoft.visdrive.sdk.ArcVisDriveEngine
import com.arcsoft.visdrive.sdk.constant.common.ArcImageFormat
import com.arcsoft.visdrive.sdk.constant.common.ArcModType
import com.arcsoft.visdrive.sdk.model.common.ArcActiveEnvParam
import com.arcsoft.visdrive.sdk.model.fr.ArcFRExtractResult
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.TimeUtils
import com.intergration.test.databinding.ActivityMainBinding
import com.intergration.test.dms.CAMERA_ID_DMS
import com.intergration.test.dms.COROUTINE_DMS
import com.intergration.test.dms.DmsCoroutineContext
import com.intergration.test.dms.DmsCoroutineScope
import com.intergration.test.dms.dmsEngine
import com.intergration.test.dms.initializeDms
import com.intergration.test.dms.setDmsAlarmCallParams
import com.intergration.test.dms.setDmsAlarmCloseEyeParams
import com.intergration.test.dms.setDmsAlarmDistractParams
import com.intergration.test.dms.setDmsAlarmDriverAbnormalParams
import com.intergration.test.dms.setDmsAlarmLensCoveredParams
import com.intergration.test.dms.setDmsAlarmSmokeParams
import com.intergration.test.dms.setDmsAlarmYawnParams
import com.intergration.test.dms.setDmsDistractScope
import com.intergration.test.dms.setDmsDrivingStatus
import com.intergration.test.dms.startDms
import com.intergration.test.fr.COROUTINE_FR
import com.intergration.test.fr.FrCoroutineContext
import com.intergration.test.fr.FrCoroutineScope
import com.intergration.test.fr.INTERVAL_COMPLETED
import com.intergration.test.fr.INTERVAL_ERROR
import com.intergration.test.fr.compareFeatureWithScore
import com.intergration.test.fr.extractRegisterFeature
import com.intergration.test.fr.extractRecognizeFeature
import com.intergration.test.fr.featureList
import com.intergration.test.fr.initializeFr
import com.intergration.test.fr.startFr
import com.intergration.test.fr.startFr1
import com.intergration.test.utils.DMS_PIC_HEIGHT
import com.intergration.test.utils.DMS_PIC_WIDTH
import com.intergration.test.utils.DOT_PREFACE_DURATION
import com.intergration.test.utils.TTS_ENGINE
import com.intergration.test.utils.VIDEO_FOLDER
import com.intergration.test.utils.VIDEO_FOLDER_
import com.intergration.test.utils.toByteBuffer
import com.mediatek.smartplatform.PreviewSource
import com.mediatek.smartplatform.RecordConfiguration
import com.mediatek.smartplatform.RecordSource
import com.mediatek.smartplatform.SmartPlatformManager
import com.mediatek.smartplatform.SpmCameraDevice
import com.mediatek.smartplatform.SpmCameraDevice.VideoCallback
import com.mediatek.smartplatform.VideoInfoMap
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.util.Locale
import java.util.concurrent.CancellationException

class MainActivity : AppCompatActivity(),TextToSpeech.OnInitListener,VideoCallback{

    private var dmsCoroutineScope: DmsCoroutineScope? =null

    private var frCoroutineScope: FrCoroutineScope? =null

    private lateinit var binding: ActivityMainBinding

    private val smartPlatformManager by lazy {
        SmartPlatformManager.get()
    }

    private val recordConfiguration = RecordConfiguration.get(RecordSource.GENERAL_CAMERA).apply {
        mCamcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P)
        mOutPutFilePath = VIDEO_FOLDER
        mVideoCycleDeleteFileNum = 3
        mLockFileNamePrefix = "dms-"
        mVideoCallback = this@MainActivity
    }

    private var dmsJob:Job? = null

    private var frJob:Job? = null

    private val requestCameraPermission = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){ granted->
        if (granted.values.any().not()) {
            Toast.makeText(this@MainActivity, "请开启权限", Toast.LENGTH_SHORT).show()
            finish()
        }
    }

    private val tts by lazy {
        val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val sb2value =am.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
        am.setStreamVolume(AudioManager.STREAM_MUSIC, sb2value, 0)
        val bundle = Bundle()
        bundle.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME,1.0f)
        TextToSpeech(this,this, TTS_ENGINE)
    }

    private var dmsCameraDevice:SpmCameraDevice? = null

    private var frCameraDevice:SpmCameraDevice? = null

    private var videoCameraDevice:SpmCameraDevice? = null

    @OptIn(FlowPreview::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        if (!allPermissionsGranted()) {
            requestCameraPermission.launch(REQUIRED_PERMISSIONS)
        }
        binding.startDms.setOnClickListener {
            LogUtils.file("点击开始DMS按钮")
            if (dmsCoroutineScope == null) {
                dmsCameraDevice = SmartPlatformManager.get().openCameraDevice(CAMERA_ID_DMS)
                dmsCameraDevice?.setErrorCallback { i, s, spmCameraDevice ->
                    LogUtils.file("error camera id:${spmCameraDevice.cameraId},event id:$i,content:$s")
                    LogUtils.e("error camera id:${spmCameraDevice.cameraId},event id:$i,content:$s")
                }
                dmsCoroutineScope = DmsCoroutineScope(DmsCoroutineContext(engine = dmsEngine,dmsCameraDevice!!) + Dispatchers.IO + COROUTINE_DMS)
            }
            LogUtils.d("dms context:${dmsCoroutineScope?.coroutineContext}")
            dmsJob = dmsCoroutineScope?.launch {
                LogUtils.d("startDms")
                try {
                    dmsCameraDevice?.setPreviewSurface(binding.dmsPreview.holder.surface,
                        PreviewSource.GENERAL_CAMERA)
                    dmsCameraDevice?.startPreview()
                    dmsCameraDevice?.startRecord(RecordSource.GENERAL_CAMERA,recordConfiguration)
                    var result = ArcVisDriveEngine.activate(APP_ID, APP_SECRET, arrayOf(ArcModType.TYPE_DMS,ArcModType.TYPE_FR),
                        ArcActiveEnvParam().apply {
                            this.IMEI = DEVICE_IMEI
                            this.storagePath = getExternalFilesDir("")?.path
                        })
                    if (result == ArcErrorInfo.ARC_ERROR_OK) {
                        LogUtils.d("DMS,FR激活成功")
                        LogUtils.file("DMS,FR激活成功")
                    } else {
                        LogUtils.e("DMS,FR激活失败")
                        LogUtils.file("DMS,FR激活失败")
                        return@launch
                    }
                    result = coroutineContext[DmsCoroutineContext]?.engine?.initializeDms()?:ArcErrorInfo.ARC_ERROR_NOT_ACTIVATED
                    if (result == ArcErrorInfo.ARC_ERROR_OK) {
                        LogUtils.d("DMS初始化成功")
                        LogUtils.file("DMS初始化成功")
                    } else {
                        LogUtils.e("DMS初始化失败")
                        LogUtils.file("DMS初始化失败")
                        return@launch
                    }
                    coroutineContext[DmsCoroutineContext]?.engine?.let {engine->
                        engine.setDmsAlarmCallParams()
                        engine.setDmsAlarmSmokeParams()
                        engine.setDmsAlarmCloseEyeParams()
                        engine.setDmsAlarmYawnParams()
                        engine.setDmsAlarmDistractParams()
                        engine.setDmsAlarmDriverAbnormalParams()
                        engine.setDmsAlarmLensCoveredParams()
                        engine.setDmsDrivingStatus()
                        engine.setDmsDistractScope()
                    }
                    coroutineContext[DmsCoroutineContext]?.engine?.let {engine->
                        withContext(Dispatchers.Main){
                            binding.countDown.visibility = View.VISIBLE
                            binding.countDown.text = "10s"
                        }
                        var startTime = System.currentTimeMillis()
                       launch(Dispatchers.Default) {
                            var i = 9
                            while (isActive && i > 0){
                                delay(1000)
                                withContext(Dispatchers.Main) {
                                    binding.countDown.text = "${i--}s"
                                }
                            }
                            withContext(Dispatchers.Main){
                                binding.countDown.visibility = View.GONE
                            }
                        }
                        dmsCameraDevice?.startDms(engine)?.collect{result->
                            ensureActive()
                            if (System.currentTimeMillis() - startTime < 10) {
                                LogUtils.e("标定失败")
                                LogUtils.file("标定失败")
                                binding.detectResult.text = "标定失败"
                                cancel("标定失败")
                            }
                            binding.detectResult.text = result
                            tts.speak(result, TextToSpeech.QUEUE_ADD, null,null)
                            launch(Dispatchers.IO){
                                ensureActive()
                                dmsCameraDevice?.lockRecordingVideo(
                                    DOT_PREFACE_DURATION,"",RecordSource.GENERAL_CAMERA)
                            }
                            launch(Dispatchers.IO) {
                                repeat(3){
                                    ensureActive()
                                    dmsCameraDevice?.takePicture(
                                        "${Environment.getExternalStorageDirectory().path}/waytous/alarm/dms-${TimeUtils.millis2String(System.currentTimeMillis(),"yyyyMMdd-HHmmss")}.jpg",
                                        {  }, { i, s, s2 ->  }
                                    )
                                    delay(1000)
                                }
                            }
                        }
                    }
                } catch (e: CancellationException) {
                    LogUtils.e("${e.message}")
                    if (e.message == "标定失败"){
                        withContext(NonCancellable+Dispatchers.Main){
                            binding.countDown.visibility = View.GONE
                            Toast.makeText(this@MainActivity,"标定失败，请重新开始",Toast.LENGTH_SHORT).show()
                        }
                    }
                    dmsCameraDevice?.stopPreview()
                    dmsCameraDevice?.stopRecord(RecordSource.GENERAL_CAMERA)
                    dmsCameraDevice?.let { smartPlatformManager.closeCameraDevice(it)}
                    dmsCameraDevice = null
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }
        binding.stopDms.setOnClickListener {
            LogUtils.file("点击停止DMS按钮")
            if (binding.countDown.visibility == View.VISIBLE) {
                binding.countDown.visibility = View.GONE
                binding.countDown.text = "10s"
            }
            if (dmsJob?.isActive == true) {
                dmsJob?.cancel(CancellationException("停止DMS检测"))
                dmsCoroutineScope = null
            } else {
                LogUtils.d("DMS协程已经执行完成")
                LogUtils.file("DMS协程已经执行完成")
                dmsCameraDevice?.stopPreview()
                dmsCameraDevice?.stopRecord(RecordSource.GENERAL_CAMERA)
                dmsCameraDevice?.let { smartPlatformManager.closeCameraDevice(it)}
            }

        }

        binding.startDms.setOnLongClickListener {
            val videoConfiguration = RecordConfiguration.get(RecordSource.GENERAL_CAMERA).apply {
                mCamcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P)
                mOutPutFilePath = VIDEO_FOLDER_
                mOutPutFileName = "video_${TimeUtils.millis2String(System.currentTimeMillis(),"yyyyMMdd_HHmmss")}"
                mVideoCycleDeleteFileNum = 3
                mVideoCallback = this@MainActivity
            }
            videoCameraDevice = SmartPlatformManager.get().openCameraDevice(CAMERA_ID_DMS)
            videoCameraDevice?.setErrorCallback { i, s, spmCameraDevice ->
                LogUtils.file("error camera id:${spmCameraDevice.cameraId},event id:$i,content:$s")
                LogUtils.e("error camera id:${spmCameraDevice.cameraId},event id:$i,content:$s")
            }
            videoCameraDevice?.setPreviewSurface(binding.dmsPreview.holder.surface,
                PreviewSource.GENERAL_CAMERA)
            videoCameraDevice?.startPreview()
            videoCameraDevice?.startRecord(RecordSource.GENERAL_CAMERA,videoConfiguration)
            true
        }

        binding.stopDms.setOnLongClickListener {
            videoCameraDevice?.stopRecord(RecordSource.GENERAL_CAMERA)
            videoCameraDevice?.stopPreview()
            SmartPlatformManager.get().closeCameraDevice(videoCameraDevice)
            true
        }

        binding.startFr.setOnClickListener {
            LogUtils.file("点击开始人脸识别按钮")
            if (frCoroutineScope == null) {
                frCameraDevice = SmartPlatformManager.get().openCameraDevice(CAMERA_ID_DMS).also { it.parameters }
                frCameraDevice?.setErrorCallback { i, s, spmCameraDevice ->
                    LogUtils.file("error camera id:${spmCameraDevice.cameraId},event id:$i,content:$s")
                    LogUtils.e("error camera id:${spmCameraDevice.cameraId},event id:$i,content:$s")
                }
//                frCameraDevice?.takePicture(File(
//                    Environment.getExternalStorageDirectory(),
//                    "fr/male.jpg"
//                ).path,null,null)
                frCoroutineScope = FrCoroutineScope(FrCoroutineContext(engine = dmsEngine) + Dispatchers.Default + COROUTINE_FR)
            }
            frJob = frCoroutineScope?.launch {
                try {
                    val activateResult = ArcVisDriveEngine.activate(APP_ID, APP_SECRET, arrayOf(ArcModType.TYPE_DMS,ArcModType.TYPE_FR),
                        ArcActiveEnvParam().apply {
                            this.IMEI = DEVICE_IMEI
                            this.storagePath = getExternalFilesDir("")?.path
                        })
                    if (activateResult == ArcErrorInfo.ARC_ERROR_OK) {
                        LogUtils.d("DMS,FR激活成功")
                    } else {
                        LogUtils.e("DMS,FR激活失败")
                        return@launch
                    }
                    val engine = coroutineContext[FrCoroutineContext]?.engine
                    frCameraDevice?.setPreviewSurface(binding.dmsPreview.holder.surface,
                        PreviewSource.GENERAL_CAMERA)
                    frCameraDevice?.startPreview()

                    val result = engine?.initializeFr()
                    LogUtils.eTag("fr","初始化结果:$result")
                    if (result == ArcErrorInfo.ARC_ERROR_OK) {
                        engine.extractRegisterFeature(
                            File(
                                Environment.getExternalStorageDirectory(),
                                "fr/"
                            ).path
                        )
//                        frCameraDevice?.startFr()?.sample(5000)?.collect {data->
//                            LogUtils.d("received data from camera")
//                            ensureActive()
//                            val liveExtractResult = engine.extractRecognizeFeature(DMS_PIC_WIDTH, DMS_PIC_HEIGHT, data)
//                            val isRecognition = engine.compareFeatureWithScore(liveExtractResult)
//                            if (isRecognition) {
//                                tts.speak("人脸识别成功", TextToSpeech.QUEUE_ADD, null, null)
//                                binding.detectResult.text = "人脸识别成功"
//                            } else {
//                                tts.speak("人脸识别失败", TextToSpeech.QUEUE_ADD, null, null)
//                                binding.detectResult.text = "人脸识别失败"
//                            }
//                        }
                        while (isActive) {
                            val data = frCameraDevice?.startFr1()
                            val liveExtractResult = ArcFRExtractResult()
                            val extractRecognizeResult = engine.extractRecognizeFeature(DMS_PIC_WIDTH,DMS_PIC_HEIGHT,
                                ArcImageFormat.ARC_IMAGE_FORMAT_NV21,data?.toByteBuffer(),liveExtractResult
                            )
                            LogUtils.dTag("fr","extractRecognizeResult result:$extractRecognizeResult")
                            if (extractRecognizeResult != ArcErrorInfo.ARC_ERROR_OK) {
                                delay(INTERVAL_ERROR)
                                continue
                            }
                            val isRecognition = engine.compareFeatureWithScore(liveExtractResult)
                            if (isRecognition) {
                                tts.speak("人脸识别成功", TextToSpeech.QUEUE_ADD, null, null)
                                binding.detectResult.text = "人脸识别成功"
                            } else {
                                tts.speak("人脸识别失败", TextToSpeech.QUEUE_ADD, null, null)
                                binding.detectResult.text = "人脸识别失败"
                            }
                            delay(INTERVAL_COMPLETED)
                        }
                    } else {
                        LogUtils.eTag("fr", "人脸算法初始化失败")
                        engine?.unInit()
                        frCameraDevice?.stopPreview()
                        frCameraDevice?.let { smartPlatformManager.closeCameraDevice(it)}
                    }
                } catch (e: CancellationException) {
                    LogUtils.eTag("fr","人脸识别error:${e.message}")
                    coroutineContext[FrCoroutineContext]?.engine?.unInit()
                    frCameraDevice?.stopPreview()
                    frCameraDevice?.let { smartPlatformManager.closeCameraDevice(it)}
                } catch (e: Exception) {
                    coroutineContext[FrCoroutineContext]?.engine?.unInit()
                    frCameraDevice?.stopPreview()
                    frCameraDevice?.let { smartPlatformManager.closeCameraDevice(it)}
                    e.printStackTrace()
                }
            }
        }
        binding.stopFr.setOnClickListener {
            LogUtils.file("点击停止人脸识别按钮")
            if (frJob?.isActive == true) {
                frJob?.cancel(CancellationException("停止人脸识别"))
                frCoroutineScope = null
            } else {
                LogUtils.file("人脸识别协程已经执行完成或被取消")
                LogUtils.dTag("fr","人脸识别协程已经执行完成或被取消")
            }
        }
    }

    override fun onVideoTaken(videoInfo: VideoInfoMap?) {
        CoroutineScope(Dispatchers.IO).launch {
            when(videoInfo?.getInt(VideoInfoMap.KEY_RECORDER_EVENT_TYPE)){
                VideoCallback.VIDEO_EVENT_SDCARD_FULL-> {
                    LogUtils.e("SDCard已满")
                    LogUtils.file("SDCard已满")
                    dmsCameraDevice?.stopRecord(RecordSource.GENERAL_CAMERA)
                }
                VideoCallback.VIDEO_EVENT_RECORD_SDCARD_DAMAGED-> {
                    LogUtils.e("SDCard损坏")
                    LogUtils.file("SDCard损坏")
                    dmsCameraDevice?.stopRecord(RecordSource.GENERAL_CAMERA)
                }
                VideoCallback.VIDEO_EVENT_RECORD_RECORDING_ERROR-> {
                    LogUtils.e("录制视频过程中发生错误")
                    LogUtils.file("录制视频过程中发生错误")
                    dmsCameraDevice?.stopRecord(RecordSource.GENERAL_CAMERA)
                }
                VideoCallback.VIDEO_EVENT_KEYPOINT_STOP ->{
                    LogUtils.d("录制打点视频结束")
                    LogUtils.file("录制打点视频结束")
                    dmsCameraDevice?.stopRecord(RecordSource.GENERAL_CAMERA)
                    dmsCameraDevice?.startRecord(RecordSource.GENERAL_CAMERA,recordConfiguration)
                }
            }
        }
    }

    override fun onVideoFrame(p0: ByteArray?, p1: Int, p2: Int, p3: String?, p4: Int) {

    }

    override fun onInit(status: Int) {
        if (status == TextToSpeech.SUCCESS) {
            when (tts.setLanguage(Locale.CHINA)) {
                TextToSpeech.LANG_MISSING_DATA, TextToSpeech.LANG_NOT_SUPPORTED -> {
                    LogUtils.file("TTS暂时不支持这种语音朗读")
                    Toast.makeText(this, "TTS暂时不支持这种语音朗读", Toast.LENGTH_SHORT).show()
                }
                else -> {
                    LogUtils.d("tts初始化成功！")
                    tts.setPitch(1.0f)
                    tts.setSpeechRate(1.0f)
                }
            }
        } else {
            LogUtils.file("TTS初始化失败")
            Toast.makeText(this, "TTS初始化失败", Toast.LENGTH_SHORT).show()
        }
    }

    override fun onDestroy() {
        tts.stop()
        tts.shutdown()
        dmsJob?.cancel(CancellationException("DMS-退出MainActivity"))
        frJob?.cancel(CancellationException("DMS-退出MainActivity"))
        super.onDestroy()
    }

    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(
            baseContext, it) == PackageManager.PERMISSION_GRANTED
    }

    companion object{
        const val TAG = "dms"
        const val APP_ID = "vdpoYwdwW15s8seKveftWJfsarrre9"
        const val APP_SECRET = "dCdVvhH6tqgWuPMpsvuihPQDHkssWi"
        const val DEVICE_IMEI = "d5e2f07694f674c4"
        private val REQUIRED_PERMISSIONS =
            mutableListOf (
                Manifest.permission.CAMERA,
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.CHANGE_WIFI_STATE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE,
            ).toTypedArray()
    }

}