package com.intergration.avm

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
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.visdrive.avmsdk.ArcErrorInfo
import com.arcsoft.visdrive.avmsdk.ArcVisDriveAVMEngine
import com.arcsoft.visdrive.avmsdk.constant.avm.ArcAVMType
import com.arcsoft.visdrive.avmsdk.model.avm.ArcAVMOutputImage
import com.arcsoft.visdrive.avmsdk.model.common.ArcActiveEnvParam
import com.blankj.utilcode.util.FileUtils
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.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.cancel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
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 avmStartScope:AvmCoroutineScope ?= null

    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 {
                val 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)
                    coroutineContext[AvmCoroutineContext]?.engine?.initializeAvmParams(calibResultPath,lookupPath)
                } else {
                    LogUtils.e("激活失败!")
                    withContext(Dispatchers.Main){
                        Toast.makeText(this@MainActivity,"激活失败",Toast.LENGTH_SHORT).show()
                    }
                    spUtils.put(IS_ACTIVATED,false)
                }
            }
        }
        binding.autoCalib.setOnClickListener {
            avmCoroutineScope.launch {
                coroutineContext[AvmCoroutineContext]?.engine?.autoCalib(calibResultPath,lookupPath)
            }
        }

        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())
            }
            val channel = Channel<Boolean>()
            avmStartScope?.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 {
                                        channel.send(true)
                                    }
                                }
                            }
                        }
                    )
                }
                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 {
                                        channel.send(true)
                                    }
                                }
                            }
                        }
                    )
                }
                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 {
                                        channel.send(true)
                                    }
                                }
                            }
                        }
                    )
                }
                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
                                    launch {
                                        channel.send(true)
                                    }
                                }
                            }
                        }
                    )
                }
                val outputImageList = arrayListOf<ArcAVMOutputImage>()
                while (avmInputImages.size != 4) {
                    delay(100)
                }
                LogUtils.d("准备播放融合图...")
                if (spUtils.getBoolean(CALIB_RESULT) && spUtils.getBoolean(LOOKUP_TABLE)) {
                    launch(Dispatchers.Default) {
                        while (channel.receive()) {
                            val result = coroutineContext[AvmCoroutineContext]?.engine?.drawAVM(
                                31,
                                avmInputImages,
                                outputImageList
                            )
                            if (result == ArcErrorInfo.ARC_ERROR_OK) {
                                if (outputImageList.isNotEmpty()) {
                                    feedData(outputImageList[0].imageData)
                                }
                            }
                        }
                    }
                } else {
                    withContext(Dispatchers.Main){
                        Toast.makeText(this@MainActivity,"请先进行标定",Toast.LENGTH_SHORT).show()
                    }
                }
            }
        }
        binding.stopAvm.setOnClickListener {
            avmStartScope?.launch {
                avmLeftCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                avmFrontCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                avmRightCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                avmBackCamera.stopPictureSequence(PictureSequenceSource.GENERAL_CAMERA)
                cancel(kotlinx.coroutines.CancellationException("Click Stop Avm Button"))
            }
            closeAuxiliaryPresentation()
        }
    }

    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.get().run {
            closeCameraDevice(avmFrontCamera)
            closeCameraDevice(avmBackCamera)
            closeCameraDevice(avmLeftCamera)
            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()
    }
}