package com.intergration.test.dms

import android.os.Environment
import com.arcsoft.visdrive.sdk.ArcErrorInfo
import com.arcsoft.visdrive.sdk.ArcVisDriveEngine
import com.arcsoft.visdrive.sdk.constant.common.ArcAlarmSensitivityLevel
import com.arcsoft.visdrive.sdk.constant.common.ArcImageFormat
import com.arcsoft.visdrive.sdk.constant.common.ArcModType
import com.arcsoft.visdrive.sdk.constant.dms.ArcDMSAlarmType
import com.arcsoft.visdrive.sdk.constant.dms.ArcDMSDetectMaskType
import com.arcsoft.visdrive.sdk.model.common.ArcDrivingStatus
import com.arcsoft.visdrive.sdk.model.common.ArcInitParamInfo
import com.arcsoft.visdrive.sdk.model.common.ArcInitParamInfoDetail
import com.arcsoft.visdrive.sdk.model.dms.ArcDMSAlarmParam
import com.arcsoft.visdrive.sdk.model.dms.ArcDMSDetectResult
import com.arcsoft.visdrive.sdk.model.dms.ArcDMSDistractScope
import com.arcsoft.visdrive.sdk.model.dms.ArcDMSInitParam
import com.blankj.utilcode.util.FileUtils
import com.blankj.utilcode.util.LogUtils
import com.intergration.test.utils.DMS_PIC_HEIGHT
import com.intergration.test.utils.DMS_PIC_WIDTH
import com.intergration.test.utils.toByteBuffer
import com.mediatek.smartplatform.ImageReaderEx
import com.mediatek.smartplatform.PictureConfiguration
import com.mediatek.smartplatform.PictureSequenceSource
import com.mediatek.smartplatform.SmartPlatformManager
import com.mediatek.smartplatform.SpmCameraDevice
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import java.io.Closeable
import java.io.File
import java.util.concurrent.Executors
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.CoroutineContext

val COROUTINE_DMS = CoroutineName("dms")

const val CAMERA_ID_DMS = "0"

val dmsResult by lazy {
    ArcDMSDetectResult()
}

class DmsCoroutineContext(val engine: ArcVisDriveEngine,val spmCameraDevice: SpmCameraDevice): AbstractCoroutineContextElement(DmsCoroutineContext){
    companion object Key:CoroutineContext.Key<DmsCoroutineContext>
}

class DmsCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
    override val coroutineContext: CoroutineContext = context + SupervisorJob()
    override fun close() {
        LogUtils.eTag("dms","DmsCoroutineScope.close")
        SmartPlatformManager.get().closeCameraDevice(coroutineContext[DmsCoroutineContext]?.spmCameraDevice)
        coroutineContext.cancel()
    }
}

private val dmsWorker by lazy {
    Executors.newSingleThreadExecutor()
}

val dmsEngine by lazy {
    ArcVisDriveEngine()
}

fun ArcVisDriveEngine.initializeDms():Int{
    val dmsInitParam = ArcDMSInitParam().apply {
        detectMask = ArcDMSDetectMaskType.MOD_DMS_CALL or
                ArcDMSDetectMaskType.MOD_DMS_SMOKE or
                ArcDMSDetectMaskType.MOD_DMS_CLOSE_EYE or
                ArcDMSDetectMaskType.MOD_DMS_YAWN or
                ArcDMSDetectMaskType.MOD_DMS_DISTRACT or
                ArcDMSDetectMaskType.MOD_DMS_DRIVER_ABNORMAL
    }
    val initParamDetail = ArcInitParamInfoDetail()
    initParamDetail.modType = ArcModType.TYPE_DMS
    initParamDetail.arcInitParamBase = dmsInitParam
    val arcInfoParam = ArcInitParamInfo()
    arcInfoParam.arcInitParamInfoDetailArray = Array(1) { initParamDetail }
    return init(arcInfoParam)
}

fun ArcVisDriveEngine.setDmsAlarmParams(interval:Int = 4,speedThreshold:Int = 33){
    val dmsAlarmParam = ArcDMSAlarmParam()
    val result = getDMSAlarmParam(ArcDMSAlarmType.ALARM_DMS_CALL, dmsAlarmParam)
    if (result == ArcErrorInfo.ARC_ERROR_OK) {
        dmsAlarmParam.sensitivityLevel = ArcAlarmSensitivityLevel.ALARM_SENSITIVITY_MEDIUM
        /**
         * 以下设置参数仅供测试使用，实际使用请根据真实环境设置
         */
        dmsAlarmParam.arcAlarmParam.interval = interval
        dmsAlarmParam.arcAlarmParam.speedThreshold = speedThreshold
    }
}

fun ArcVisDriveEngine.setDmsDistractScope(leftYaw:Int = -20,rightYaw:Int = 20,upPitch:Int = 20,downPitch:Int = -20):Int{
    val dmsScope = ArcDMSDistractScope()
    var result = getDMSDistractScopeParam(dmsScope)
    return if (result == ArcErrorInfo.ARC_ERROR_OK) {
        /**
         * 以下为模拟修改数值，实际使用请根据真实环境设置
         */
        dmsScope.leftYaw = leftYaw
        dmsScope.rightYaw = rightYaw
        dmsScope.upPitch = upPitch
        dmsScope.downPitch = downPitch
        setDMSDistractScopeParam(dmsScope)
    } else result
}

fun ArcVisDriveEngine.setDmsDrivingStatus(speed:Int = 50):Int{
    val driveStatus = ArcDrivingStatus()
    driveStatus.speed = speed
    return setDrivingStatus(driveStatus)
}

fun SpmCameraDevice.startDms(engin:ArcVisDriveEngine) = callbackFlow{
    val dmsDir = File(Environment.getExternalStorageDirectory(),"dms/")
    if (!FileUtils.isFileExists(dmsDir)) {
        FileUtils.createOrExistsDir(dmsDir)
    }
    val pictureConfig = PictureConfiguration.get(PictureSequenceSource.GENERAL_CAMERA)
    pictureConfig.mPath = dmsDir.absolutePath
    pictureConfig.mImageFormat = SpmCameraDevice.ImageDataCallback.IMAGE_FORMAT_NV21
    pictureConfig.mPicWidth = DMS_PIC_WIDTH
    pictureConfig.mPicHeight = DMS_PIC_HEIGHT
    pictureConfig.mDataType = SpmCameraDevice.ImageDataCallback.IMAGE_DATA_RAW
    pictureConfig.mImageCallback = ImageReaderEx.ImageCallback { _, _, _, data, _ ->
        dmsWorker.execute {
            val dmsResp = engin.detectDMS(pictureConfig.mPicWidth,pictureConfig.mPicHeight,
                ArcImageFormat.ARC_IMAGE_FORMAT_NV21,
                data.toByteBuffer(),dmsResult)
            if (dmsResp == ArcErrorInfo.ARC_ERROR_OK) {
                when (dmsResult.alarmMask) {
                    ArcDMSDetectMaskType.MOD_DMS_CALL -> {
                        trySend("打电话")
                        LogUtils.dTag("dms", "打电话")
                    }

                    ArcDMSDetectMaskType.MOD_DMS_CLOSE_EYE -> {
                        trySend( "闭眼睛")
                        LogUtils.dTag("dms", "闭眼睛")
                    }

                    ArcDMSDetectMaskType.MOD_DMS_SMOKE -> {
                        trySend("抽烟")
                        LogUtils.dTag("dms", "抽烟")
                    }

                    ArcDMSDetectMaskType.MOD_DMS_YAWN -> {
                        trySend("打哈欠报警")
                        LogUtils.dTag("dms", "打哈欠报警")
                    }

                    ArcDMSDetectMaskType.MOD_DMS_DISTRACT -> {
                        trySend("分神")
                        LogUtils.dTag("dms", "分神")
                    }

                    ArcDMSDetectMaskType.MOD_DMS_DRIVER_ABNORMAL -> {
                        trySend("驾驶员异常报警")
                        LogUtils.dTag("dms", "驾驶员异常报警")
                    }

                    ArcDMSDetectMaskType.MOD_DMS_LENS_COVERED -> {
                        trySend("遮挡镜头")
                        LogUtils.dTag("dms", "遮挡镜头")
                    }

                    ArcDMSDetectMaskType.MOD_DMS_SEATBELT_UNFASTENED -> {
                        trySend("不知道")
                        LogUtils.dTag("dms", "不知道")
                    }
                }
            } else {
                LogUtils.dTag("dms","dms检测识别，错误码:$dmsResp")
            }
        }
    }
    startPictureSequence(PictureSequenceSource.GENERAL_CAMERA,pictureConfig)
    awaitClose {
        LogUtils.dTag("dms","dms detect ended")
        stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
        engin.unInit()
    }
}