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.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.ArcModType
import com.arcsoft.visdrive.sdk.model.common.ArcActiveEnvParam
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.compareFeatureWithScore
import com.intergration.test.fr.extractFeatureFromDir
import com.intergration.test.fr.extractRecognizeFeatureFromByteArray
import com.intergration.test.fr.featureList
import com.intergration.test.fr.frCameraDevice
import com.intergration.test.fr.initializeFr
import com.intergration.test.fr.startFr
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.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.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.launch
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

    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)
                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->
                        dmsCameraDevice?.startDms(engine)?.collect{result->
                            ensureActive()
                            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}")
                    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 (dmsJob?.isActive == true) {
                dmsJob?.cancel(CancellationException("停止DMS检测"))
                dmsCoroutineScope = null
            } else {
                LogUtils.d("DMS协程已经执行完成")
                dmsCameraDevice?.stopPreview()
                dmsCameraDevice?.stopRecord(RecordSource.GENERAL_CAMERA)
                dmsCameraDevice?.let { smartPlatformManager.closeCameraDevice(it)}
            }

        }

        binding.startFr.setOnClickListener {
            LogUtils.file("点击开始人脸识别按钮")
            if (frCoroutineScope == null) {
                dmsCameraDevice = SmartPlatformManager.get().openCameraDevice(CAMERA_ID_DMS)
                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) {
                        if (featureList.isNotEmpty()) {
                            engine?.extractFeatureFromDir(
                                File(
                                    Environment.getExternalStorageDirectory(),
                                    "fr/"
                                ).path
                            )
                        }
                        var startTime = System.currentTimeMillis()
                        frCameraDevice.startFr().takeWhile { _ ->
                            System.currentTimeMillis() - startTime > 5000
                        }.collect {
                            ensureActive()
                            val liveExtractResult = engine.extractRecognizeFeatureFromByteArray(
                                DMS_PIC_WIDTH,
                                DMS_PIC_HEIGHT,
                                it
                            )
                            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 = "人脸识别失败"
                            }
                            startTime = System.currentTimeMillis()
                        }
                    } else {
                        LogUtils.eTag("fr", "人脸算法初始化失败")
                    }
                } catch (e: CancellationException) {
                    LogUtils.eTag("fr","人脸识别error:${e.message}")

                } catch (e: Exception) {
                    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("退出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()
    }

}