package com.adealink.weparty.call.manager

import android.content.Intent
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.frame.BaseFrame
import com.adealink.frame.log.Log
import com.adealink.frame.media.MediaInfo
import com.adealink.frame.router.Router
import com.adealink.frame.util.AppUtil
import com.adealink.weparty.App
import com.adealink.weparty.call.R
import com.adealink.weparty.call.constant.CALL_ERROR_CALL_FAIL_FOR_CALLING
import com.adealink.weparty.call.constant.CALL_ERROR_CALL_YOURSELF
import com.adealink.weparty.call.constant.CALL_ERROR_MEDIA_CONFLICT_CANCEL
import com.adealink.weparty.call.constant.TAG_CALL_FLOW
import com.adealink.weparty.call.data.CallReq
import com.adealink.weparty.call.datasource.remote.CallHttpService
import com.adealink.weparty.call.stat.CallAcceptEvent
import com.adealink.weparty.call.stat.CallStartEvent
import com.adealink.weparty.call.util.PermissionRequest
import com.adealink.weparty.commonui.toast.util.getFailedMsg
import com.adealink.weparty.commonui.toast.util.showToast
import com.adealink.weparty.media.MediaType
import com.adealink.weparty.module.call.Call
import com.adealink.weparty.module.call.SettingsConfig
import com.adealink.weparty.module.profile.ProfileModule
import com.tencent.cloud.tuikit.engine.call.TUICallDefine
import com.tencent.qcloud.tuicore.permission.PermissionCallback
import com.tencent.qcloud.tuikit.tuicallkit.common.utils.CallUtils
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.call.CallMediaType
import io.trtc.tuikit.atomicxcore.api.call.CallParams
import io.trtc.tuikit.atomicxcore.api.call.CallParticipantStatus
import io.trtc.tuikit.atomicxcore.api.call.CallStore
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import com.tencent.qcloud.tuikit.tuicallkit.manager.CallManager as CallEngine

val callManager: ICallManager by lazy { CallManager() }

/**
 * 1. 发起通话
 * 2. 应答通话
 * 3. 监听通话行为
 */
class CallManager : BaseFrame<ICallListener>(), ICallManager {

    private val callHttpService by lazy {
        App.instance.networkService.getHttpService(CallHttpService::class.java)
    }

    /**
     * -. 检查当前是否正在通话
     * -. 检查是否处于匹配状态
     * -. 检查当前通话信息
     * -. 检查媒体冲突
     * -. 检查/申请权限
     * -. 业务侧发起通话
     * -. 最后回调到CallStore呼叫
     */
    override fun call(
        targetUid: String,
        callback: CompletionHandler?,
    ) {
        launch {
            val callActionCallback = object : CompletionHandler {

                override fun onSuccess() {
                    Router.build(AppUtil.appContext, Call.Call.PATH)
                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        .start()
                    callback?.onSuccess()
                    CallStartEvent().apply {
                        userId to targetUid
                        result to "1"
                    }.send()
                }

                override fun onFailure(code: Int, desc: String) {
                    Log.i(TAG_CALL_FLOW, "call($targetUid) fail, code:$code, msg:$$desc")
                    callback?.onFailure(code, desc)
                    CallEngine.instance.reset()
//                    //处理媒体冲突不需要提示
                    if (code != CALL_ERROR_MEDIA_CONFLICT_CANCEL) {
                        showToast(Rlt.Failed(IError(msg = desc, serverCode = code)))
                    }
                    CallStartEvent().apply {
                        userId to targetUid
                        result to "2"
                    }.send()
                }

            }

            //判断当前是否通话中
            if (CallUtils.isSelfInCalling()) {
                callActionCallback.onFailure(
                    CALL_ERROR_CALL_FAIL_FOR_CALLING,
                    getCompatString(R.string.call_fail_for_calling_now)
                )
                return@launch
            }

            if (targetUid == ProfileModule.getMyUid()) {
                //不能呼叫自己
                callActionCallback.onFailure(
                    CALL_ERROR_CALL_YOURSELF,
                    getCompatString(R.string.call_target_uid_is_self)
                )
                return@launch
            }

            //房间媒体冲突处理失败,APP同时打开多个媒体房间
            val mediaConflictRlt = App.instance.mediaManager.conflictHandle(
                MediaInfo(
                    MediaType.CALL_1V1.type,
                    getCompatString(R.string.call_chat)
                )
            )
            if (mediaConflictRlt is Rlt.Failed) {
                Log.e(TAG_CALL_FLOW, "call fail, for media conflict fail")
                callActionCallback.onFailure(CALL_ERROR_MEDIA_CONFLICT_CANCEL, "")
                return@launch
            }

            //检查/申请权限
            val permissionRlt = requestPermission(true)
            if (permissionRlt is Rlt.Failed) {
                Log.e(TAG_CALL_FLOW, "call fail, for permission denied")
                callActionCallback.onFailure(
                    TUICallDefine.ERROR_PERMISSION_DENIED,
                    getCompatString(R.string.call_permission_grant_fail)
                )
                return@launch
            }

            val startCallRlt = startCall(targetUid)
            if (startCallRlt is Rlt.Failed) {
                callActionCallback.onFailure(
                    startCallRlt.error.serverCode,
                    getFailedMsg(startCallRlt.error)
                )
                return@launch
            }

            //发起通话请求
            val callParams = createCallParams()
            CallEngine.instance.calls(
                listOf(targetUid),
                CallMediaType.Audio,
                callParams,
                callActionCallback
            )
        }
    }

    /**
     *
     * -. 检查当前通话信息
     * -. 检查媒体冲突
     * -. 检查/申请权限
     * -. 业务侧发起通话
     * -. 最后回调到CallStore接通
     */
    override fun accept(callback: CompletionHandler?) {
        launch {
            val isSelfCaller = CallUtils.isSelfCaller()
            val callerUid = CallUtils.getCaller()
            val calleeUid = CallUtils.getCallee()

            val acceptCallback = object : CompletionHandler {
                override fun onSuccess() {
                    Router.build(AppUtil.appContext, Call.Call.PATH)
                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        .start()
                    callback?.onSuccess()
                    CallAcceptEvent().apply {
                        userId to if (isSelfCaller) calleeUid else callerUid
                        result to "1"
                    }.send()
                }

                override fun onFailure(code: Int, desc: String) {
                    Log.i(TAG_CALL_FLOW, "accept fail, code:$code, msg:$$desc")
                    CallStore.shared.reject(null)
                    callback?.onFailure(code, desc)
                    //处理媒体冲突不需要提示
                    if (code != CALL_ERROR_MEDIA_CONFLICT_CANCEL) {
                        showToast(
                            Rlt.Failed(IError(msg = desc, serverCode = code))
                        )
                    }
                    CallAcceptEvent().apply {
                        userId to if (isSelfCaller) calleeUid else callerUid
                        result to "2"
                    }.send()
                }
            }


            if (callerUid.isNullOrEmpty() || calleeUid.isNullOrEmpty()) {
                Log.e(
                    TAG_CALL_FLOW,
                    "accept fail, callerUid($callerUid)/calledUid($calleeUid) is invalid."
                )
                acceptCallback.onFailure(
                    TUICallDefine.ERROR_PARAM_INVALID,
                    getCompatString(R.string.call_target_uid_is_invalid)
                )
                return@launch
            }

            //检查/申请权限
            val permissionRlt = requestPermission(isSelfCaller)
            if (permissionRlt is Rlt.Failed) {
                Log.e(TAG_CALL_FLOW, "accept fail, permission denied")
                acceptCallback.onFailure(
                    TUICallDefine.ERROR_PERMISSION_DENIED,
                    getCompatString(R.string.call_permission_grant_fail)
                )
                return@launch
            }

            //业务侧发起通话
            val startCallRlt = startCall(callerUid)
            if (startCallRlt is Rlt.Failed) {
                acceptCallback.onFailure(startCallRlt.error.serverCode, startCallRlt.error.msg)
                return@launch
            }
            //接受通话
            CallStore.shared.accept(acceptCallback)
        }
    }

    override suspend fun requestPermission(isCaller: Boolean): Rlt<Any> {
        return withContext(Dispatcher.UI) {
            suspendCancellableCoroutine { continuation ->
                PermissionRequest.requestPermissions(
                    AppUtil.appContext,
                    CallMediaType.Audio,
                    object : PermissionCallback() {
                        override fun onGranted() {
                            //主叫直接返回结果
                            if (isCaller) {
                                if (continuation.isActive) {
                                    continuation.resume(Rlt.Success(Any()), null)
                                }
                                return
                            }
                            //被叫需要检查当前呼叫状态
                            if (CallUtils.getSelfCallStatus() == CallParticipantStatus.None) {
                                if (continuation.isActive) {
                                    continuation.resume(Rlt.Failed(IError()), null)
                                }
                            } else {
                                if (continuation.isActive) {
                                    continuation.resume(Rlt.Success(Any()), null)
                                }
                            }
                        }

                        override fun onDenied() {
                            if (continuation.isActive) {
                                continuation.resume(Rlt.Failed(IError()), null)
                            }
                        }
                    })
            }
        }
    }

    private suspend fun startCall(calledUid: String): Rlt<Any> {
        val startCallRlt = callHttpService.startCall(
            CallReq(calledUid)
        )
        return startCallRlt
    }

    private suspend fun createCallParams(): CallParams {
        return withContext(this.coroutineContext) {
            val callParams = CallParams()
            //通话超时时间
            callParams.timeout = SettingsConfig.callTimeOut
            //用户数据(透传数据)
//            callParams.userData = toJsonErrorNull(
//                CallUserData(callRoomId, source?.source ?: CallerSource.CALLER.source, matchId)
//            )
            callParams
        }
    }

}