package ai.guiji.duix.cloud.display.ui.activity

import ai.guiji.duix.cloud.display.databinding.ActivityDisplayBinding
import ai.guiji.duix.cloud.display.ui.dialog.AudioUrlInputDialog
import ai.guiji.duix.cloud.display.ui.dialog.DriveModeDialog
import ai.guiji.duix.cloud.display.ui.dialog.QuestionInputDialog
import ai.guiji.duix.cloud.display.ui.dialog.TextInputDialog
import ai.guiji.duix.sdk.cloud.Player
import ai.guiji.duix.sdk.cloud.VirtualFactory
import ai.guiji.duix.sdk.cloud.bean.DUIXBean
import android.annotation.SuppressLint
import android.content.Context
import android.media.AudioManager
import android.os.Bundle
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.Toast
import org.webrtc.EglBase
import org.webrtc.RendererCommon
import org.webrtc.SurfaceViewRenderer
import org.webrtc.VideoTrack


class DisplayActivity : BaseActivity() {

    private lateinit var binding: ActivityDisplayBinding

    private var player: Player? = null

    private var eglBase = EglBase.create()
    private var eglBaseContext = eglBase.eglBaseContext

    private var mCurrentDriveMode = DriveModeDialog.MODE_MICROPHONE

    private var backFacing = false

    private var localRenderer: SurfaceViewRenderer?=null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val appId = intent.getStringExtra("appId")
        val appSecret = intent.getStringExtra("appSecret")
        val conversationId = intent.getStringExtra("conversationId")
        val audioManager = mContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
        audioManager.isSpeakerphoneOn = true
        keepScreenOn()
        binding = ActivityDisplayBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.tvMode.setOnClickListener {
            val driveModeDialog = DriveModeDialog(mContext, object : DriveModeDialog.ClickListener{
                override fun onClick(mode: Int) {
                    updateDriveMode(mode)
                }
            })
            driveModeDialog.show()
        }
        binding.tvAudioDriveInput.setOnClickListener {
            val audioUrlInputDialog = AudioUrlInputDialog(mContext, object : AudioUrlInputDialog.ClickListener{
                override fun onResult(url: String) {
                    audioUrlDrive(url)
                }
            })
            audioUrlInputDialog.show()
        }
        binding.tvTextDriveInput.setOnClickListener {
            val textInputDialog = TextInputDialog(mContext, object : TextInputDialog.ClickListener{
                override fun onResult(text: String) {
                    textDrive(text)
                }
            })
            textInputDialog.show()
        }
        binding.tvQuestionDriveInput.setOnClickListener {
            val questionInputDialog = QuestionInputDialog(mContext, object : QuestionInputDialog.ClickListener{
                override fun onResult(question: String) {
                    textQADrive(question)
                }
            })
            questionInputDialog.show()
        }
        binding.tvInterruptPlayback.setOnClickListener {
            interruptPlay()
        }
        binding.tvSwitchCamera.setOnClickListener {
            backFacing = !backFacing
            player?.backFacing(backFacing)
        }

        binding.tvCloseCamera.setOnClickListener {
            player?.closeCamera()
            binding.layoutCamera.removeAllViews()
        }
        binding.tvOpenCamera.setOnClickListener {
            player?.openCamera()
            binding.layoutCamera.addView(
                localRenderer,
                0,
                RelativeLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT
                )
            )
        }

        binding.render.init(eglBaseContext, null)
        binding.render.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)
        binding.render.setMirror(false)
        binding.render.setEnableHardwareScaler(false /* enabled */)

        localRenderer = SurfaceViewRenderer(mContext)
        localRenderer?.init(eglBaseContext, null)
        localRenderer?.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)
        localRenderer?.setMirror(false)
        localRenderer?.setEnableHardwareScaler(false /* enabled */)



        VirtualFactory.init(appId, appSecret)

        player = VirtualFactory.getPlayer(mContext, eglBaseContext)
        player?.addCallback(object : Player.Callback {
            override fun onShow() {
                Log.d(TAG, "onShow")
            }

            override fun onReady() {
                Log.d(TAG, "onReady")
            }

            @SuppressLint("SetTextI18n")
            override fun onError(msgType: Int, msgSubType: Int, msg: String?) {
                runOnUiThread {
                    binding.tvMessage.visibility = View.VISIBLE
                    binding.tvMessage.text = "Session error: msgType: $msgType msgSubType: $msgSubType msg: $msg"
                    Log.e(
                        TAG,
                        "Session error: msgType: $msgType msgSubType: $msgSubType msg: $msg"
                    )
                    Toast.makeText(
                        mContext,
                        "Session error: msgType: $msgType msgSubType: $msgSubType msg: $msg",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }

            override fun onAsrResult(text: String?, sentenceEnd: Boolean) {
                Log.e(TAG, "onAsrResult: $text, sentenceEnd: $sentenceEnd")
                text?.let { showAsrResult(it, sentenceEnd) }

            }

            override fun onVideoTrack(
                track: VideoTrack,
            ) {
                runOnUiThread {
                    track.addSink(binding.render)
                }
            }

            override fun onCameraTrack(track: VideoTrack) {
                runOnUiThread {
                    track.addSink(localRenderer)
                }
            }

            override fun onSpeakText(text: String?) {
                super.onSpeakText(text)
                Log.e(TAG, "onSpeakText: $text")
            }

            override fun onSessionInfo(duixBean: DUIXBean?) {
                super.onSessionInfo(duixBean)
                runOnUiThread {
                    Log.e(TAG, "duixBean: $duixBean")
                    if (duixBean?.supportMultiModel() == true){
                        binding.tvSwitchCamera.visibility = View.VISIBLE
                        binding.tvCloseCamera.visibility = View.VISIBLE
                        binding.tvOpenCamera.visibility = View.VISIBLE
                    }
                }
            }
        })
        player?.connect(conversationId)
    }


    override fun onDestroy() {
        super.onDestroy()
        player?.release()
        binding.render.release()
        localRenderer?.release()
        eglBase?.release()
    }

    private fun updateDriveMode(mode: Int){
        mCurrentDriveMode = mode
        when(mode){
            DriveModeDialog.MODE_MICROPHONE -> {
                player?.setMicrophoneMute(false)
                binding.tvMicrophoneDriveHint.visibility = View.VISIBLE
                binding.tvAudioDriveInput.visibility = View.GONE
                binding.tvTextDriveInput.visibility = View.GONE
                binding.tvQuestionDriveInput.visibility = View.GONE
            }
            DriveModeDialog.MODE_AUDIO -> {
                player?.setMicrophoneMute(true)
                binding.tvMicrophoneDriveHint.visibility = View.GONE
                binding.tvAudioDriveInput.visibility = View.VISIBLE
                binding.tvTextDriveInput.visibility = View.GONE
                binding.tvQuestionDriveInput.visibility = View.GONE
            }
            DriveModeDialog.MODE_TEXT -> {
                player?.setMicrophoneMute(true)
                binding.tvMicrophoneDriveHint.visibility = View.GONE
                binding.tvAudioDriveInput.visibility = View.GONE
                binding.tvTextDriveInput.visibility = View.VISIBLE
                binding.tvQuestionDriveInput.visibility = View.GONE
            }
            DriveModeDialog.MODE_TEXT_QA -> {
                player?.setMicrophoneMute(true)
                binding.tvMicrophoneDriveHint.visibility = View.GONE
                binding.tvAudioDriveInput.visibility = View.GONE
                binding.tvTextDriveInput.visibility = View.GONE
                binding.tvQuestionDriveInput.visibility = View.VISIBLE
            }
        }
    }

    private fun audioUrlDrive(url: String){
        player?.speakWithWav(url, true)
    }

    private fun textDrive(text: String){
        player?.speakWithTxt(text, true)
    }

    private fun textQADrive(question: String){
        player?.speakWithQuestion(question, true)
    }

    private fun interruptPlay(){
        player?.stopAudio()
    }

    private fun showAsrResult(text: String, end: Boolean){
        runOnUiThread {
            if (end){
                binding.tvAsrResult.text = text
                mHandler.postDelayed(hideAsrResult, 1000)
            } else {
                mHandler.removeCallbacks(hideAsrResult)
                binding.tvAsrResult.text = text
                binding.tvAsrResult.visibility = View.VISIBLE
            }
        }
    }

    private val hideAsrResult = Runnable {
        runOnUiThread {
            binding.tvAsrResult.text = ""
            binding.tvAsrResult.visibility = View.INVISIBLE
        }
    }
}
