package com.adealink.weparty.profile.edit.dialog.fragment

import android.Manifest
import android.annotation.SuppressLint
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import com.adealink.frame.aab.util.getCompatString
import com.adealink.frame.base.Rlt
import com.adealink.frame.ext.isViewBindingValid
import com.adealink.frame.log.Log
import com.adealink.frame.mvvm.view.viewBinding
import com.adealink.frame.util.onClick
import com.adealink.frame.util.runOnUiThread
import com.adealink.weparty.commonui.BaseFragment
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.module.profile.data.getDuration
import com.adealink.weparty.permission.PermissionUtils
import com.adealink.weparty.profile.R
import com.adealink.weparty.profile.databinding.FragmentTalentVoiceEditBinding
import com.adealink.weparty.profile.edit.dialog.EditTalentVoiceDialog
import com.adealink.weparty.profile.edit.dialog.viewmodel.EditVoicePage
import com.adealink.weparty.profile.edit.dialog.viewmodel.EditVoiceViewModel
import com.adealink.weparty.profile.viewmodel.ProfileViewModel
import com.adealink.weparty.profile.viewmodel.ProfileViewModelFactory
import com.adealink.weparty.storage.file.FilePath
import com.adealink.weparty.util.formatMissTime
import com.adealink.weparty.viewmodel.parentFragmentViewModels
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 java.util.Timer
import java.util.TimerTask
import kotlin.coroutines.resume
import kotlin.math.max
import com.adealink.weparty.R as APP_R

class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {

    companion object {
        private const val TAG = "VoiceEditFragment"
    }

    private val binding by viewBinding(FragmentTalentVoiceEditBinding::bind)

    private val editViewModel by parentFragmentViewModels<EditVoiceViewModel, EditTalentVoiceDialog>(
        EditTalentVoiceDialog::class.java
    )

    private val profileViewModel by activityViewModels<ProfileViewModel> { ProfileViewModelFactory() }

    private var recordTimer: Timer? = null
    private var recordTimes = 0
    private var isRecording: Boolean = false


    private var previewTimer: Timer? = null
    private var previewTimes = 0
    private var isPreviewPause = false

    override fun initViews() {
        super.initViews()
        binding.btnRecord.onClick {
            clickRecord()
        }
        binding.btnReRecord.onClick {
            clickReRecord()
        }
        binding.btnPreview.onClick {
            audioPreview()
        }
        binding.btnSubmit.onClick {
            submit()
        }
    }

    override fun observeViewModel() {
        super.observeViewModel()
        editViewModel.voiceDataLD.observeWithoutCache(viewLifecycleOwner) {
            if (it.path.isNullOrEmpty()) {
                binding.clRecord.show()
                binding.clPreview.gone()
                binding.btnSubmit.isEnabled = false
            } else {
                binding.clRecord.gone()
                binding.clPreview.show()
                binding.btnSubmit.isEnabled = true
                previewTimes = editViewModel.voiceDataLD.value.getDuration()
                binding.tvPreviewDuration.text = formatMissTime(previewTimes)
            }
        }
    }

    override fun loadData() {
        super.loadData()
        isRecording = false
        editViewModel.setVoiceData(null)
    }

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

    private fun clickReRecord() {
        editViewModel.setVoiceData(null)
        resetRecord()
        startRecord()
    }

    private fun audioPreview() {
        stopRecord()
        val voicePath = editViewModel.voiceDataLD.value?.path
        if (voicePath.isNullOrEmpty()) {
            return
        }
        AudioPlayer.getInstance().stopPlay()
        AudioPlayer.getInstance().startPlay(voicePath, object : AudioPlayer.Callback {
            override fun onPlayStart() {
                Log.d(TAG, "audioPreview, onPlayStart")
                if (!isViewBindingValid()) {
                    return
                }
                onPreviewStart()
            }

            override fun onCompletion(success: Boolean?) {
                Log.d(TAG, "audioPreview, onCompletion")
                if (!isViewBindingValid()) {
                    return
                }
                resetPreview()
            }
        })
    }

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

        Log.d(TAG, "startAudioRecord")
        val audioPath = "${FilePath.audioPath}voice_edit.m4a"
        AudioRecorder.startRecord(audioPath, object : AudioRecorderCallback {
            override fun onStarted() {
                if (!isViewBindingValid()) {
                    return
                }
                Log.d(TAG, "startAudioRecord, onStarted")
                onRecordStart()
            }

            override fun onFinished(outputPath: String?) {
                if (!isViewBindingValid()) {
                    return
                }
                Log.d(TAG, "startAudioRecord, onFinished:$outputPath")
                resetRecord()
                val duration = AudioRecorder.getDuration(outputPath).toLong()
                if (duration < 3000) {
                    showToast(APP_R.string.profile_record_voice_less_than_3_seconds)
                    editViewModel.setVoiceData(null, null)
                    return
                }
                editViewModel.setVoiceData(outputPath, duration)
            }

            override fun onFailed(errorCode: Int, errorMessage: String?) {
                if (!isViewBindingValid()) {
                    return
                }
                Log.d(
                    TAG,
                    "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,
                    "record audio failed, errorCode $errorCode, errorMessage $errorMessage"
                )
                binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_record_ic)
            }

            override fun onCanceled() {
                if (!isViewBindingValid()) {
                    return
                }
                Log.d(TAG, "startAudioRecord, onCanceled")
                resetRecord()
                binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_record_ic)
            }
        })
    }

    private fun requestPermission() {
        val act = activity ?: return
        viewLifecycleOwner.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 onRecordStart() {
        isRecording = true
        if (recordTimer == null) {
            recordTimer = Timer()
        }
        recordTimer?.schedule(object : TimerTask() {
            override fun run() {
                runOnUiThread {
                    recordTimes++
                    if (isViewBindingValid()) {
                        binding.tvDuration.text = formatMissTime(recordTimes)
                    }
                }
            }
        }, 0, 1000)
        binding.tvDurationTips.text =
            getCompatString(R.string.profile_edit_talent_voice_stop)
        binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_stop_ic)
    }

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

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


    private fun onPreviewStart() {
        isPreviewPause = false
        previewTimes = editViewModel.voiceDataLD.value.getDuration()
        if (previewTimer == null) {
            previewTimer = Timer()
        }
        previewTimer?.schedule(object : TimerTask() {
            override fun run() {
                runOnUiThread {
                    if (isPreviewPause) {
                        return@runOnUiThread
                    }
                    previewTimes = max(previewTimes - 1, 0)
                    if (isViewBindingValid()) {
                        binding.tvPreviewDuration.text = formatMissTime(previewTimes)
                    }
                }
            }
        }, 0, 1000)

        binding.btnPreview.setImageResource(APP_R.drawable.profile_edit_talent_voice_preview_pause_ic)
        binding.btnPreview.onClick {
            pausePreview()
        }
    }

    private fun pausePreview() {
        isPreviewPause = true
        AudioPlayer.getInstance().pausePlay()
        binding.btnPreview.setImageResource(APP_R.drawable.profile_edit_talent_voice_preview_ic)
        binding.btnPreview.onClick {
            resumePreview()
        }
    }

    private fun resumePreview() {
        isPreviewPause = false
        AudioPlayer.getInstance().resumePlay()
        binding.btnPreview.setImageResource(APP_R.drawable.profile_edit_talent_voice_preview_pause_ic)
        binding.btnPreview.onClick {
            pausePreview()
        }
    }

    @SuppressLint("SetTextI18n")
    private fun resetPreview() {
        isPreviewPause = false
        previewTimer?.cancel()
        previewTimer = null
        previewTimes = 0
        binding.tvPreviewDuration.text = formatMissTime(editViewModel.voiceDataLD.value.getDuration())
        binding.btnPreview.setImageResource(APP_R.drawable.profile_edit_talent_voice_preview_ic)
        binding.btnPreview.onClick {
            audioPreview()
        }
    }

    private fun submit() {
        showLoading()
        editViewModel.submit().observe(viewLifecycleOwner) { rlt ->
            dismissLoading()
            showToast(rlt)
            when (rlt) {
                is Rlt.Failed -> {
                    //Ntd.
                }

                is Rlt.Success -> {
                    profileViewModel.pullMyUserInfo()
                    editViewModel.showPage(EditVoicePage.REVIEW)
                }
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        recordTimer?.cancel()
        recordTimer = null
        AudioRecorder.stopRecord()

        previewTimer?.cancel()
        previewTimer = null
        AudioPlayer.getInstance().stopPlay()
    }

}