package com.intergration.avm

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.arcsoft.imageutil.ArcSoftImageFormat
import com.arcsoft.imageutil.ArcSoftImageUtil
import com.arcsoft.visdrive.avmsdk.ArcErrorInfo
import com.arcsoft.visdrive.avmsdk.ArcVisDriveAVMEngine
import com.arcsoft.visdrive.avmsdk.constant.avm.ArcAVMType
import com.arcsoft.visdrive.avmsdk.model.avm.ArcAVMCalibInfo
import com.arcsoft.visdrive.avmsdk.model.avm.ArcAVMCalibResult
import com.arcsoft.visdrive.avmsdk.model.avm.ArcAVMLookupTable
import com.arcsoft.visdrive.avmsdk.model.avm.ArcAVMOutputImage
import com.arcsoft.visdrive.avmsdk.model.common.ArcActiveEnvParam
import com.arcsoft.visdrive.avmsdk.model.common.ArcRect
import com.blankj.utilcode.util.FileUtils
import com.blankj.utilcode.util.ImageUtils
import com.blankj.utilcode.util.LogUtils
import com.intergration.avm.databinding.ActivityMainBinding
import com.intergration.avm.utils.ArcAVMInputImageFactory
import com.intergration.avm.utils.CALIB_RESULT
import com.intergration.avm.utils.IMAGE_HEIGHT
import com.intergration.avm.utils.IMAGE_WIDTH
import com.intergration.avm.utils.IS_ACTIVATED
import com.intergration.avm.utils.LOOKUP_TABLE
import com.intergration.avm.utils.closeAuxiliaryPresentation
import com.intergration.avm.utils.feedData
import com.intergration.avm.utils.openAuxiliaryPresentation
import com.intergration.avm.utils.spUtils
import com.mediatek.smartplatform.PictureSequenceSource
import com.mediatek.smartplatform.PreviewSource
import com.mediatek.smartplatform.SmartPlatformManager
import com.mediatek.smartplatform.SpmCameraDevice
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

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

    private val launchSettingsActivity = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
        if (it.resultCode == RESULT_OK) {
            LogUtils.d("分屏权限设置成功！")
        }
    }

    private val avmDir =  File(Environment.getExternalStorageDirectory(), "avm/")

    private val calibResultPath by lazy {
        File(getExternalFilesDir("avm"),"calibresult.dat")
    }

    private val lookupPath by lazy {
        File(getExternalFilesDir("avm"),"lookuptable.dat")
    }

    private var job:Job? = null

    private var avmPlayJob:Job? = null

    private var avmStartScope:AvmCoroutineScope ?= null

    private val channel = Channel<Boolean>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        if (allPermissionsGranted()) {
            LogUtils.e("allPermissionsGranted...")
            startPreview()
            CoroutineScope(Dispatchers.IO).launch {
                if (!FileUtils.isFileExists(avmDir)) {
                    FileUtils.createOrExistsDir(avmDir)
                }
            }
        } else {
            ActivityCompat.requestPermissions(
                this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
        }
        if (!Settings.canDrawOverlays(this@MainActivity)) {
            val intent = Intent(
                Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:$packageName")
            )
            launchSettingsActivity.launch(intent)
            Toast.makeText(this@MainActivity, "需要取得权限以使用悬浮窗", Toast.LENGTH_SHORT).show()
        }
        binding.activeAvm.setOnClickListener {
            avmCoroutineScope.launch {
                var result = ArcVisDriveAVMEngine.activate(
                    APP_ID, APP_SECRET, ArcAVMType.AVM_CAM_4,
                    ArcActiveEnvParam().apply {
                        this.IMEI = "d5e2f07694f674c4"
                        this.storagePath = getExternalFilesDir("")?.path
                    })
                if (result == ArcErrorInfo.ARC_ERROR_OK) {
                    LogUtils.d("激活成功!")
                    withContext(Dispatchers.Main){
                        Toast.makeText(this@MainActivity,"激活成功",Toast.LENGTH_SHORT).show()
                    }
                    spUtils.put(IS_ACTIVATED,true)
                    result = coroutineContext[AvmCoroutineContext]?.engine?.initializeAvmParams(calibResultPath,lookupPath)?:ArcErrorInfo.ARC_ERROR_BAD_STATE
                    if (result == ArcErrorInfo.ARC_ERROR_OK) {
                        val getCalibInfo = ArcAVMCalibInfo()
                        val getCalibResult = ArcAVMCalibResult()
                        val getLookupTable = ArcAVMLookupTable()
                        result = avmEngine.getCalibrateResults(getCalibInfo, getCalibResult, getLookupTable)
                        LogUtils.i("getCalibrateResults:${result}, calibInfo:${getCalibInfo}, result:${getCalibResult.data.size}, lookup:${getLookupTable.data.size}")
                    }
                } else {
                    LogUtils.e("激活失败!")
                    withContext(Dispatchers.Main){
                        Toast.makeText(this@MainActivity,"激活失败",Toast.LENGTH_SHORT).show()
                    }
                    spUtils.put(IS_ACTIVATED,false)
                }
            }
        }
        binding.autoCalib.setOnClickListener {
            avmCoroutineScope.launch {
                launch(Dispatchers.Default) {
                    avmFrontCamera.startPictureSequence(
                        PictureSequenceSource.GENERAL_CAMERA,
                        configCameraSequence(avmDir.absolutePath){ _, _, status, data, _ ->
                            if (status == SpmCameraDevice.ImageDataCallback.IMAGE_STATUS_SUCCEEDED) {
                                ArcAVMInputImageFactory.ofFront(data).also {
                                    avmInputImages[0] = it
                                }
                            }
                        }
                    )
                }
                launch(Dispatchers.Default) {
                    avmRightCamera.startPictureSequence(
                        PictureSequenceSource.GENERAL_CAMERA,
                        configCameraSequence(avmDir.absolutePath){ _, _, status, data, _ ->
                            if (status == SpmCameraDevice.ImageDataCallback.IMAGE_STATUS_SUCCEEDED) {
                                ArcAVMInputImageFactory.ofRight(data).also {
                                    avmInputImages[1] = it
                                }
                            }
                        }
                    )
                }
                launch(Dispatchers.Default) {
                    avmBackCamera.startPictureSequence(
                        PictureSequenceSource.GENERAL_CAMERA,
                        configCameraSequence(avmDir.absolutePath){ _, _, status, data, _ ->
                            if (status == SpmCameraDevice.ImageDataCallback.IMAGE_STATUS_SUCCEEDED) {
                                ArcAVMInputImageFactory.ofBack(data).also {
                                    avmInputImages[2] = it
                                }
                            }
                        }
                    )
                }
                launch(Dispatchers.Default) {
                    avmLeftCamera.startPictureSequence(
                        PictureSequenceSource.GENERAL_CAMERA,
                        configCameraSequence(avmDir.absolutePath){ _, _, status, data, _ ->
                            if (status == SpmCameraDevice.ImageDataCallback.IMAGE_STATUS_SUCCEEDED) {
                                ArcAVMInputImageFactory.ofLeft(data).also {
                                    avmInputImages[3] = it
                                }
                            }
                        }
                    )
                }
                while (avmInputImages.filterNotNull().size != 4) {
                    LogUtils.d("input list size:${avmInputImages.filterNotNull()}")
                    delay(100)
                }
                val result = coroutineContext[AvmCoroutineContext]?.engine?.autoCalib(calibResultPath,lookupPath)
                if (result != null) {
                    launch(Dispatchers.IO){
                        avmLeftCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                        avmFrontCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                        avmRightCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                        avmBackCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                    }
                }
            }
        }

        binding.manualCalib.setOnClickListener {
            avmCoroutineScope.launch {
                coroutineContext[AvmCoroutineContext]?.engine?.manualCalib(calibResultPath,lookupPath)
            }
        }
        binding.startAvm.setOnClickListener {
            openAuxiliaryPresentation()
            if (avmStartScope == null) {
                avmStartScope = AvmCoroutineScope(AvmCoroutineContext(engine = avmEngine) + Dispatchers.IO + COROUTINE_AVM + Job())
            }
            avmPlayJob = avmStartScope?.launch {
                try {
                    avmFrontCamera.startPictureSequence(
                        PictureSequenceSource.GENERAL_CAMERA,
                        configCameraSequence(avmDir.absolutePath) { _, _, status, data, _ ->
                            if (status == SpmCameraDevice.ImageDataCallback.IMAGE_STATUS_SUCCEEDED) {
                                ArcAVMInputImageFactory.ofFront(data).also {
                                    avmInputImages[0] = it
                                    launch {
                                        ensureActive()
                                        channel.send(true)
                                    }
                                }
                            }
                        }
                    )
                    avmRightCamera.startPictureSequence(
                        PictureSequenceSource.GENERAL_CAMERA,
                        configCameraSequence(avmDir.absolutePath) { _, _, status, data, _ ->
                            if (status == SpmCameraDevice.ImageDataCallback.IMAGE_STATUS_SUCCEEDED) {
                                ArcAVMInputImageFactory.ofRight(data).also {
                                    avmInputImages[1] = it
                                    launch {
                                        ensureActive()
                                        channel.send(true)
                                    }
                                }
                            }
                        }
                    )
                    avmBackCamera.startPictureSequence(
                        PictureSequenceSource.GENERAL_CAMERA,
                        configCameraSequence(avmDir.absolutePath) { _, _, status, data, _ ->
                            if (status == SpmCameraDevice.ImageDataCallback.IMAGE_STATUS_SUCCEEDED) {
                                ArcAVMInputImageFactory.ofBack(data).also {
                                    avmInputImages[2] = it
                                    launch {
                                        ensureActive()
                                        channel.send(true)
                                    }
                                }
                            }
                        }
                    )
                    avmLeftCamera.startPictureSequence(
                        PictureSequenceSource.GENERAL_CAMERA,
                        configCameraSequence(avmDir.absolutePath) { _, _, status, data, _ ->
                            if (status == SpmCameraDevice.ImageDataCallback.IMAGE_STATUS_SUCCEEDED) {
                                ArcAVMInputImageFactory.ofLeft(data).also {
                                    avmInputImages[3] = it
                                    launch {
                                        ensureActive()
                                        channel.send(true)
                                    }
                                }
                            }
                        }
                    )
                    val outputImageList = arrayListOf<ArcAVMOutputImage>()
                    while (avmInputImages.filterNotNull().size != 4) {
                        delay(100)
                    }
                    LogUtils.d("准备播放融合图...")
                    if (spUtils.getBoolean(CALIB_RESULT) && spUtils.getBoolean(LOOKUP_TABLE)) {
                        val rect = ArcRect()
                        avmEngine.getCarModelRect(rect)
                        LogUtils.i("车模位置:$rect")
                        while (channel.receive()) {
                            ensureActive()
                            val result = coroutineContext[AvmCoroutineContext]?.engine?.drawAVM(
                                31,
                                avmInputImages,
                                outputImageList
                            )
                            var i = 0
                            val downBitmap = BitmapFactory.decodeResource(resources,R.mipmap.mars_little)
                            val nv21DataDown = ArcSoftImageUtil.createImageData(downBitmap.width, downBitmap.height, ArcSoftImageFormat.NV21)
                            ArcSoftImageUtil.bitmapToImageData(downBitmap, nv21DataDown, ArcSoftImageFormat.NV21)
                            if (result == ArcErrorInfo.ARC_ERROR_OK) {
                                if (outputImageList.isNotEmpty()) {
                                    for (row in rect.top until rect.bottom){
                                        LogUtils.i("row = $row")
                                        for (index in rect.left until  rect.right) {
                                            outputImageList[0].imageData[index + (row -1) * IMAGE_HEIGHT] = nv21DataDown[i++]
                                        }
                                    }
                                    feedData(outputImageList[0].imageData,outputImageList[0].width,outputImageList[0].height)
                                }
                            }
                        }
                    } else {
                        withContext(Dispatchers.Main) {
                            Toast.makeText(this@MainActivity, "请先进行标定", Toast.LENGTH_SHORT)
                                .show()
                        }
                    }
                } catch (e: CancellationException) {
                    LogUtils.e("${e.message}")
                    closeAuxiliaryPresentation()
                    avmLeftCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                    avmFrontCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                    avmRightCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                    avmBackCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                } catch (e: Throwable) {
                    e.printStackTrace()
                }
            }
        }
        binding.stopAvm.setOnClickListener {
            if (avmPlayJob?.isActive == true) {
                avmPlayJob?.cancel(CancellationException("结束AVM实时渲染"))
            } else {
                closeAuxiliaryPresentation()
                avmLeftCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                avmFrontCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                avmRightCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                avmBackCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
            }
        }
    }

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

    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>, grantResults:
        IntArray) {
        LogUtils.e("onRequestPermissionsResult")
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {
                startPreview()
                CoroutineScope(Dispatchers.IO).launch {
                    if (!FileUtils.isFileExists(avmDir)) {
                        FileUtils.createOrExistsDir(avmDir)
                    }
                }
            } else {
                Toast.makeText(this,
                    "Permissions not granted by the user.",
                    Toast.LENGTH_SHORT).show()
                finish()
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }

    override fun onDestroy() {
        super.onDestroy()
        smartPlatformManager.closeCameraDevice(avmFrontCamera)
        smartPlatformManager.closeCameraDevice(avmBackCamera)
        smartPlatformManager.closeCameraDevice(avmLeftCamera)
        smartPlatformManager.closeCameraDevice(avmRightCamera)
        job?.cancel(CancellationException("MainActivity Destroyed"))
    }

    private fun startPreview(){
        job = MainScope().launch {
            while (!smartPlatformManager.isServiceAlive){
                LogUtils.e("SmartPlatformService had not started,waiting for it starting")
                delay(500)
            }
            LogUtils.d("SmartPlatformService had started")
            try {
                withContext(Dispatchers.IO) {
                    avmFrontCamera.setPreviewSurface(binding.frontPreview.holder.surface,
                        PreviewSource.GENERAL_CAMERA_EX)
                    avmFrontCamera.startPreview()
                    LogUtils.d("avmFrontCamera id:${avmFrontCamera.cameraId}")
                }
                withContext(Dispatchers.IO) {
                    avmRightCamera.setPreviewSurface(binding.rightPreview.holder.surface,
                        PreviewSource.GENERAL_CAMERA_EX)
                    avmRightCamera.startPreview()
                    LogUtils.d("avmRightCamera id:${avmRightCamera.cameraId}")
                }
                withContext(Dispatchers.IO) {
                    avmBackCamera.setPreviewSurface(binding.backPreview.holder.surface,
                        PreviewSource.GENERAL_CAMERA_EX)
                    avmBackCamera.startPreview()
                    LogUtils.d("avmBackCamera id:${avmBackCamera.cameraId}")
                }
                withContext(Dispatchers.IO) {
                    avmLeftCamera.setPreviewSurface(binding.leftPreview.holder.surface,
                        PreviewSource.GENERAL_CAMERA_EX)
                    avmLeftCamera.startPreview()
                    LogUtils.d("avmLeftCamera id:${avmLeftCamera.cameraId}")
                }
            } catch (e: Exception) {
                LogUtils.e("${e.message}")
                avmLeftCamera.stopPreview()
                avmFrontCamera.stopPreview()
                avmRightCamera.stopPreview()
                avmBackCamera.stopPreview()
            }
        }
    }

    companion object {

        private val APP_ID = "vdpoYwdwW15s8seKveftWJfsarrre9"
        private val APP_SECRET = "dCdVvhH6tqgWuPMpsvuihPQDHkssWi"

        private const val REQUEST_CODE_PERMISSIONS = 10
        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()
    }
}