package com.adealink.weparty.module.widget.form.field.voice

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.adealink.frame.aab.util.getCompatString
import com.adealink.frame.base.IError
import com.adealink.frame.base.Rlt
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.log.Log
import com.adealink.frame.util.onClick
import com.adealink.frame.util.runOnUiThread
import com.adealink.weparty.commonui.commonSelectedDrawable
import com.adealink.weparty.commonui.ext.getActivity
import com.adealink.weparty.commonui.ext.gone
import com.adealink.weparty.commonui.ext.show
import com.adealink.weparty.commonui.toast.util.showToast
import com.adealink.weparty.databinding.WidgetVoiceBinding
import com.adealink.weparty.module.profile.data.VoiceData
import com.adealink.weparty.module.profile.data.sameWith
import com.adealink.weparty.permission.PermissionUtils
import com.adealink.weparty.storage.file.FilePath
import com.adealink.weparty.util.formatMissTime
import com.adealink.weparty.util.uploadVoice
import com.adealink.weparty.module.widget.form.BaseWidgetView
import com.adealink.weparty.module.widget.form.IWidgetData
import com.adealink.weparty.module.widget.form.WidgetType
import com.adealink.weparty.module.widget.form.data.StepField
import com.adealink.weparty.module.widget.form.data.StepFieldValue
import com.adealink.weparty.module.widget.form.data.StringStepField
import com.adealink.weparty.module.widget.form.data.StringStepFieldValue
import com.adealink.weparty.module.widget.form.data.TAG_WIDGET_VOICE
import com.adealink.weparty.module.widget.form.data.UnSupportFieldDataException
import com.tencent.qcloud.tuicore.TUIConstants.TUICalling
import com.tencent.qcloud.tuikit.tuichat.component.audio.AudioPlayer
import com.tencent.qcloud.tuikit.tuichat.component.audio.AudioRecorder
import com.tencent.qcloud.tuikit.tuichat.component.audio.AudioRecorder.AudioRecorderCallback
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import java.util.Timer
import java.util.TimerTask
import kotlin.coroutines.resume
import com.adealink.weparty.R as APP_R


class VoiceWidgetData(
    override val fieldData: StepField<*>
) : IWidgetData {
    override fun widgetType(): WidgetType {
        return WidgetType.VOICE
    }

}

@SuppressLint("SetTextI18n")
class VoiceWidgetView(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0,
) : BaseWidgetView<VoiceWidgetData>(context, attrs, defStyle) {

    private val binding = WidgetVoiceBinding.inflate(LayoutInflater.from(context), this)

    var recordListener: OnRecordListener? = null
    private var initVoiceData: VoiceData? = null

    private var mTimer: Timer? = null
    private var times = 0
    private var isRecording: Boolean = false
    private var voiceData: VoiceData? = null

    override fun checkWidgetValid(widget: VoiceWidgetData) {
        if ((widget.fieldData !is StringStepField)) {
            throw UnSupportFieldDataException(
                getCompatString(
                    APP_R.string.common_widget_config_error,
                    widget.fieldData.fieldName,
                    getCompatString(APP_R.string.common_widget_value_type_string)
                )
            )
        }
    }

    fun setTopTitleVisible(visible: Boolean) {
        binding.clTop.show(visible)
    }

    fun getVoiceData(): VoiceData? {
        return voiceData
    }

    fun setVoiceData(data: VoiceData?) {
        voiceData = data
        onVoiceDataChanged()
    }

    override fun onViewCreated(lifecycleOwner: LifecycleOwner, widget: VoiceWidgetData) {
        super.onViewCreated(lifecycleOwner, widget)
        if (widget.fieldData.fieldName.isEmpty()) {
            binding.tvTitle.gone()
        } else {
            binding.tvTitle.show()
            binding.tvTitle.text = widget.fieldData.fieldName
        }
        if (widget.fieldData.fieldDesc.isEmpty()) {
            binding.tvDesc.gone()
        } else {
            binding.tvDesc.show()
            binding.tvDesc.text = widget.fieldData.fieldDesc
        }

        if (widget.fieldData.example?.isValid() == true) {
            binding.btnExample.background = commonSelectedDrawable()
            binding.btnExample.show()
            binding.btnExample.onClick {
                showExampleDialog()
            }
        } else {
            binding.btnExample.gone()
        }

        //录音部分
        binding.btnRecord.onClick {
            clickRecord()
        }
        binding.btnReRecord.onClick {
            clickReRecord()
        }

        val currentValue = (widgetData?.fieldData as? StringStepField)?.fieldValue
        voiceData = if (currentValue.isNullOrEmpty()) {
            null
        } else {
            VoiceData(url = currentValue, null)
        }
        initVoiceData = voiceData
        onVoiceDataChanged()
    }

    private fun onVoiceDataChanged() {
        if (voiceData == null || voiceData?.isNull() == true) {
            binding.clRecord.show()
            binding.clPreview.gone()
            binding.btnPreview.setSound(voiceData)
            recordListener?.onRecordInfoChanged(null)
        } else {
            binding.clRecord.gone()
            binding.clPreview.show()
            binding.btnPreview.setSound(voiceData)
            recordListener?.onRecordInfoChanged(null)
        }
    }


    private fun clickRecord() {
        if (!isRecording) {
            //启动录制
            startRecord()
        } else {
            stopRecord()
        }
    }

    private fun clickReRecord() {
        voiceData = null
        onVoiceDataChanged()
        resetRecord()
        startRecord()
    }

    private fun startRecord() {
        //录音前关闭音频播放
        AudioPlayer.getInstance().stopPlay()

        Log.d(TAG_WIDGET_VOICE, "startAudioRecord")
        val audioPath =
            "${FilePath.audioPath}${widgetData?.fieldData?.fieldCode ?: "voice_widget"}.m4a"
        AudioRecorder.startRecord(audioPath, object : AudioRecorderCallback {
            override fun onStarted() {
                recordListener?.onRecordStart()
                recordListener?.onRecordInfoChanged(null)
                Log.d(TAG_WIDGET_VOICE, "startAudioRecord, onStarted")
                isRecording = true
                if (mTimer == null) {
                    mTimer = Timer()
                }
                mTimer?.schedule(object : TimerTask() {
                    override fun run() {
                        runOnUiThread {
                            times++
                            if (isAttachedToWindow) {
                                binding.tvDuration.text = formatMissTime(times)
                            }
                        }
                    }
                }, 0, 1000)
                binding.tvDurationTips.text =
                    getCompatString(APP_R.string.profile_edit_talent_voice_stop)
                binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_stop_ic)
            }

            override fun onFinished(outputPath: String?) {
                recordListener?.onRecordFinish(false)
                Log.d(TAG_WIDGET_VOICE, "startAudioRecord, onFinished:$outputPath")
                resetRecord()
                val duration = AudioRecorder.getDuration(outputPath).toLong()
                if (duration < 3000) {
                    showToast(APP_R.string.profile_record_voice_less_than_3_seconds)
                    voiceData = null
                    onVoiceDataChanged()
                    return
                }
                voiceData = VoiceData(url = null, path = outputPath, duration = duration)
                onVoiceDataChanged()
            }

            override fun onFailed(errorCode: Int, errorMessage: String?) {
                recordListener?.onRecordFinish(true)
                Log.d(
                    TAG_WIDGET_VOICE,
                    "startAudioRecord, onFailed, errorCode:$errorCode, errorMessage:$errorMessage"
                )
                resetRecord()
                if (errorCode == TUICalling.ERROR_MIC_PERMISSION_REFUSED) {
                    //没有授予权限
                    requestPermission()
                } else if (errorCode == AudioRecorder.ERROR_CODE_MIC_IS_BEING_USED || errorCode == TUICalling.ERROR_STATUS_IN_CALL) {
                    showToast(APP_R.string.common_mic_is_being_used_cant_record)
                } else {
                    showToast(APP_R.string.common_record_audio_failed)
                }
                Log.e(
                    TAG_WIDGET_VOICE,
                    "record audio failed, errorCode $errorCode, errorMessage $errorMessage"
                )
                binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_record_ic)
            }

            override fun onCanceled() {
                Log.d(TAG_WIDGET_VOICE, "startAudioRecord, onCanceled")
                resetRecord()
                binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_record_ic)
            }
        })
    }

    private fun requestPermission() {
        val act = context.getActivity() ?: return
        act.lifecycleScope.launch {
            val granted = requestPermission(act)
            if (granted) {
                startRecord()
            }
        }
    }

    private val permissions = arrayOf(Manifest.permission.RECORD_AUDIO)
    private suspend fun requestPermission(activity: FragmentActivity): Boolean {
        return suspendCancellableCoroutine { coroutine ->
            if (PermissionUtils.hasPermissions(activity, *permissions)) {
                if (coroutine.isActive) {
                    coroutine.resume(true)
                }
                return@suspendCancellableCoroutine
            }
            PermissionUtils.requestPermissions(
                activity,
                permissions.toList(),
                getCompatString(APP_R.string.profile_record_voice_permission_request_tips),
                onGranted = {
                    if (coroutine.isActive) {
                        coroutine.resume(true)
                    }
                },
                onDenied = {
                    if (coroutine.isActive) {
                        coroutine.resume(false)
                    }
                }
            )
        }
    }

    private fun stopRecord() {
        AudioRecorder.stopRecord()
    }

    @SuppressLint("SetTextI18n")
    private fun resetRecord() {
        isRecording = false
        mTimer?.cancel()
        mTimer = null
        times = 0
        if (isAttachedToWindow) {
            binding.tvDuration.text = "00:00"
            binding.tvDurationTips.text =
                getCompatString(APP_R.string.profile_edit_talent_voice_record)
            binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_record_ic)
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        AudioPlayer.getInstance().stopPlay()
        AudioRecorder.stopRecord()
    }

    override fun validate(): Rlt<Any> {
        val widgetData = widgetData
        if (widgetData == null) {
            return Rlt.Success(Unit)
        }
        if (widgetData.fieldData.validate?.required == true) {
            if (voiceData == null || voiceData?.path.isNullOrEmpty()) {
                return Rlt.Failed(
                    IError(
                        getCompatString(
                            APP_R.string.common_widget_voice_validate_require_fail,
                            widgetData.fieldData.fieldName
                        )
                    )
                )
            }
        }
        return Rlt.Success(Unit)

    }

    override suspend fun beforeSubmit(): Rlt<Any> {
        return withContext(Dispatcher.WENEXT_THREAD_POOL) {
            val validateRlt = validate()
            if (validateRlt is Rlt.Failed) {
                return@withContext Rlt.Success(Unit)
            }
            val voiceData = voiceData
            if (voiceData == null) {
                return@withContext Rlt.Success(Unit)
            }
            if (!voiceData.url.isNullOrEmpty()) {
                //已经上传了
                return@withContext Rlt.Success(Unit)
            }
            return@withContext uploadVoice(voiceData, false)
        }
    }

    override fun getFieldValue(): StepFieldValue? {
        val widgetData = widgetData ?: return null
        return StringStepFieldValue(
            widgetData.fieldData.fieldCode,
            voiceData?.url
        ).apply {
            duration = ((voiceData?.duration ?: 0) / 1000).toInt()
        }
    }

    override fun hasEditFieldValue(): Boolean {
        val initData = initVoiceData
        val currentData = voiceData
        return !initData.sameWith(currentData)
    }

    interface OnRecordListener {
        fun onRecordInfoChanged(voiceData: VoiceData?)
        fun onRecordStart()
        fun onRecordFinish(fail: Boolean)
    }

}