package com.ydl.audioim

import android.annotation.SuppressLint
import android.content.Context
import android.os.Handler
import android.text.TextUtils
import com.alibaba.android.arouter.launcher.ARouter
import com.apm.insight.log.VLog
import com.google.gson.Gson
import com.ydl.audioim.bean.AgoraInvitationBean
import com.ydl.audioim.http.AudioApiRequestUtil
import com.ydl.audioim.http.IMEvent
import com.ydl.audioim.http.command.ConnectExceptionCommand
import com.ydl.audioim.router.AudioImIn
import com.ydl.audioim.utils.AudioLogUtils
import com.ydl.audioim.utils.AudioLogUtils.Companion.writeAgoraLog
import com.ydl.audioim.utils.onConfideEvent
import com.ydl.consultantim.ConsultantAudioHomeActivity
import com.ydl.ydl_av.messge_service.YDLRTMClient
import com.ydl.ydl_av.messge_service.bean.RTMMesssage
import com.ydl.ydl_av.messge_service.callback.CallListener
import com.ydl.ydl_av.messge_service.callback.CancelCallStatusListener
import com.ydl.ydl_av.messge_service.callback.InitListener
import com.ydl.ydl_av.messge_service.callback.LoginCallback
import com.ydl.ydl_av.messge_service.request.LoginParam
import com.ydl.ydl_av.messge_service.response.CallLocalResponse
import com.ydl.ydl_av.messge_service.response.CallRemoteResponse
import com.ydl.ydl_av.voice.manager.YDLVoiceManager
import com.ydl.ydlcommon.app.Apm
import com.ydl.ydlcommon.modular.ModularServiceManager
import com.ydl.ydlcommon.utils.ActivityManager
import com.ydl.ydlcommon.utils.LogUtil
import com.ydl.ydlcommon.utils.log.AliYunLogConfig
import com.ydl.ydlcommon.utils.log.AliYunRichLogsHelper
import com.ydl.ydlcommon.utils.log.LogHelper
import com.yidianling.im.api.bean.IMSendCustomNotificationResultCallBack
import com.yidianling.user.api.event.UserLogoutEvent
import com.yidianling.user.api.service.IUserService
import de.greenrobot.event.EventBus
import io.agora.rtm.RtmStatusCode
import io.agora.rtm.RtmStatusCode.ConnectionChangeReason.CONNECTION_CHANGE_REASON_REMOTE_LOGIN
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.util.*
import java.util.concurrent.TimeUnit

/**
 * @author harvie
 * @date 2019/9/27
 * 语音通话入口类
 */
class YDLavManager {

    companion object {
        const val FILE_NAME = "consult.log"
        private const val TAG = "YDLavManager"

        //当前sdk的登录状态
        var sdkStatus = -1
        var isOnlineRtm = true // 账号在多端登录情况下判断RTM否在线，仅仅用在RTM互踢情况下判断是否在线，其它场景慎用

        val instances: YDLavManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            YDLavManager()
        }
        const val AUDIO_NO_AUTH_ERROR_CODE = "97"//音频权限未通过错误码

        var currentChannelId: String? = null
    }


    fun init(context: Context, appId: String) {
        YDLRTMClient.instances.init(context, appId, listener)
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this)
        }
        //设置回调
        setCallback()

        val uid = ModularServiceManager.provide(IUserService::class.java).getUserInfo()?.uid
        if (!TextUtils.isEmpty(uid) && !TextUtils.equals("0", uid)) {
            //不延时，可能会导致请求api报 network not unablibale
            Handler().postDelayed({
                login(uid)
            }, 300)
        }
    }

    public fun onEvent(event: UserLogoutEvent) {
        instances.logout()
    }

    private fun setCallback() {
        YDLRTMClient.instances.setCallListener(object : CallListener {
            override fun onCallRecivedByPeer(response: CallLocalResponse?) {
                //返回给主叫：被叫已收到呼叫邀请
                LogUtil.e("[agora]${response?.calleeId}已收到呼叫邀请，频道号${response?.ChannelId}")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "${response?.calleeId}已收到呼叫邀请，频道号${response?.ChannelId}"
                )
                AudioApiRequestUtil.reportCallEvent(response?.ChannelId, IMEvent(IMEvent.Event.onPeerReceived))

                val dimension = hashMapOf("call" to "call_received_by_peer")
                onConfideEvent(dimension, response?.ChannelId)
                val act = ActivityManager.getInstance().getTopTaskActivity()
                if (act is AudioHomeActivity) {
                    act.runOnUiThread {
                        act.playWaitingMusic()
                        act.writeAgoraLog("被叫已收到通话邀请")
                    }
                }
            }

            override fun onCallAccepted(response: CallLocalResponse?, msg: String?) {
                //返回给主叫
                LogUtil.e("[agora]${response?.calleeId}已接收呼叫邀请")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "${response?.calleeId}已接收呼叫邀请"
                )
                AudioApiRequestUtil.reportCallEvent(response?.ChannelId, IMEvent(IMEvent.Event.onPeerAccepted))
                currentChannelId = response?.ChannelId
                //加入声网频道时机修改：主叫收到被叫接受邀请的回调后再加入声网频道
                val act = ActivityManager.getInstance().getTopTaskActivity()
                if (act is AudioHomeActivity) {
                    act.runOnUiThread {
                        act.joinChannel()
                        act.onPeerAccepted()
                    }
                }
            }

            override fun onCallRefused(response: CallLocalResponse?, msg: String?) {
                //返回给主叫
                LogUtil.e("[agora]${response?.calleeId}已拒绝呼叫邀请")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "${response?.calleeId}已拒绝呼叫邀请"
                )
                AudioApiRequestUtil.reportCallEvent(response?.ChannelId, IMEvent(IMEvent.Event.onPeerRejected))
                val dimension = hashMapOf("call" to "call_refused")
                onConfideEvent(dimension, response?.ChannelId)
                val act = ActivityManager.getInstance().getTopTaskActivity()
                if (act is AudioHomeActivity) {
                    act.onCallRefused()
                }
            }

            override fun onCallCanceled(response: CallLocalResponse?) {
                //返回给主叫
                LogUtil.e("[agora]主叫已取消呼叫邀请")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "主叫已取消呼叫邀请"
                )
                val dimension = hashMapOf("call" to "call_canceled")
                onConfideEvent(dimension, response?.ChannelId)
                val act = ActivityManager.getInstance().getTopTaskActivity()
                if (act is AudioHomeActivity) {
                    act.runOnUiThread {
                        act.writeAgoraLog("主叫(用户)呼叫取消：超时或主动取消")
                        act.uploadExceptionStatus("已取消", 1)
                    }
                }
            }

            override fun onCallFailure(response: CallLocalResponse?, errorCode: Int, errorMsg:String?) {
                //返回给主叫
                LogUtil.e("[agora]呼叫${response?.calleeId}用户失败：${response?.response}")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "呼叫${response?.calleeId}用户失败：${response?.response},${errorCode}"
                )
                AudioApiRequestUtil.reportCallEvent(
                    response?.ChannelId,
                    IMEvent(IMEvent.Event.callFail),
                    errorCode = errorCode,
                    errorReason = errorMsg
                )
                val dimension = hashMapOf(
                    "call" to "call_fail",
                    "call_fail" to "code${errorCode}"
                )
                onConfideEvent(dimension, response?.ChannelId)
                val act = ActivityManager.getInstance().getTopTaskActivity()
                //专家离线或者30 秒后仍未收到专家响应，重新再邀请一次
                when (errorCode) {
                    //被叫不在线   呼叫邀请发出 30 秒后被叫仍未 ACK 响应呼叫邀请
                    RtmStatusCode.LocalInvitationError.LOCAL_INVITATION_ERR_PEER_OFFLINE, RtmStatusCode.LocalInvitationError.LOCAL_INVITATION_ERR_PEER_NO_RESPONSE -> {
                        if (act is AudioHomeActivity) {
                            act.runOnUiThread {
                                act.rtcCall()
                            }
                        }
                    }
                    RtmStatusCode.LocalInvitationError.LOCAL_INVITATION_ERR_INVITATION_EXPIRE -> {
                        //呼叫邀请过期。被叫 ACK 响应呼叫邀请后 60 秒呼叫邀请未被取消、接受、拒绝，则呼叫邀请过期。
                    }
                }
                //呼叫失败日志输出
                if (act is AudioHomeActivity) {
                    act.runOnUiThread {
                        act.writeAgoraLog("发送通话邀请失败：${errorCode}")
                        LogHelper.getInstance().uploadLog(false)
                    }
                }
            }

            override fun onRemoteInvitationReceived(response: CallRemoteResponse?) {
                //返回给被叫
                LogUtil.e("[agora]收到来自${response?.callerId}的呼叫邀请")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "收到来自${response?.callerId}的呼叫邀请"
                )
                receivedCall(response?.content, "来自RTM")
            }

            override fun onRemoteInvitationAccepted(response: CallRemoteResponse?) {
                //返回给被叫
                LogUtil.e("[agora]接受来自${response?.callerId}的呼叫成功")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "接受来自${response?.callerId}的呼叫成功"
                )
            }

            override fun onRemoteInvitationRefused(response: CallRemoteResponse?) {
                //返回给被叫
                LogUtil.e("[agora]已拒绝来自${response?.callerId}的呼叫")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "已拒绝来自${response?.callerId}的呼叫"
                )
                val act = ActivityManager.getInstance().getTopTaskActivity()
                if (act is ConsultantAudioHomeActivity) {
                    act.uploadExceptionStatus("已拒绝", 2)
                }
            }

            override fun onRemoteInvitationCanceled(response: CallRemoteResponse?) {
                callEndStatusUpdate(response?.ChannelId!!, 1, "主叫取消呼叫")
                //返回给被叫
                LogUtil.e("[agora]主叫${response?.callerId}已取消呼叫邀请")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "主叫${response?.callerId}已取消呼叫邀请"
                )
                writeAgoraLog(
                    "呼叫邀请被取消：主叫(专家)主动取消-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}",
                    FILE_NAME
                )

                val act = ActivityManager.getInstance().getTopTaskActivity()
                if (act is ConsultantAudioHomeActivity) {
                    act.uploadExceptionStatus("对方已取消", 1)
                }

                closePage()
            }

            override fun onRemoteInvitationFailure(response: CallRemoteResponse?, errorCode: Int) {
                //返回给被叫
                LogUtil.e("[agora]来自主叫${response?.callerId}的呼叫邀请进程失败:${response?.response}")
                if (errorCode == RtmStatusCode.RemoteInvitationError.REMOTE_INVITATION_ERR_INVITATION_EXPIRE) { //呼叫邀请过期
                    AliYunRichLogsHelper.getInstance().sendRichLog(
                        AliYunLogConfig.AGORA,
                        "呼叫邀请被取消：用户未接听"
                    )
                    writeAgoraLog(
                        "呼叫邀请被取消：用户未接听-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}",
                        FILE_NAME
                    )
                    val act = ActivityManager.getInstance().getTopTaskActivity()
                    if (act is ConsultantAudioHomeActivity) {
                        act.uploadExceptionStatus("未接听", 3)
                    }
                } else {
                    writeAgoraLog(
                        "呼叫邀请被取消：错误原因(${errorCode})", FILE_NAME
                    )
                    AliYunRichLogsHelper.getInstance().sendRichLog(
                        AliYunLogConfig.AGORA,
                        "呼叫邀请被取消：错误原因(${errorCode})"
                    )
                }
                callEndStatusUpdate(response?.ChannelId!!, 8, "超时未接听导致的取消呼叫")
                //关闭页面
                closePage()
            }

            override fun onCallSuccess(response: CallLocalResponse?) {
                AudioApiRequestUtil.reportCallEvent(response?.ChannelId, IMEvent(IMEvent.Event.callSuccess))
            }
        })
    }

    fun rtcCall(listenerUid: String?, channelId: String?, sendDoctocrMsg: String?) {
        YDLRTMClient.instances.call(listenerUid, channelId, sendDoctocrMsg)
        AudioApiRequestUtil.reportCallEvent(channelId, IMEvent(IMEvent.Event.startCall))
        sendCustomNotification(listenerUid!!, sendDoctocrMsg!!, "1")
    }

    fun acceptCall(toUid: String, channelId: String?, data: String) {
        YDLRTMClient.instances.acceptCall(channelId)
        sendCustomNotification(toUid, data, "2")
    }

    fun refuseCall(toUid: String, channelId: String?, data: String) {
        YDLRTMClient.instances.refuseCall(channelId)
        sendCustomNotification(toUid, data, "4")
    }

    fun cancelCall(
        listenerUid: String,
        channelId: String,
        data: String,
        event: (msg: String?, code: Int) -> Unit
    ) {
        YDLRTMClient.instances.cancelCall(
            listenerUid,
            channelId,
            object : CancelCallStatusListener {
                override fun onFailure(errorMsg: String?, errorCode: Int) {
                    event(errorMsg, errorCode)
                    YDLRTMClient.instances.cancelCall(listenerUid, channelId, null)
                }

                override fun onSuccess() {
                }
            })

        callEndStatusUpdate(channelId, 1, "主叫取消呼叫")
        AudioApiRequestUtil.reportCallEvent(channelId, IMEvent(IMEvent.Event.callCancel))
        sendCustomNotification(listenerUid, data, "3")
    }

    private fun sendCustomNotification(toUid: String, data: String, callType: String) {
        val infoBean = AgoraInvitationBean()
        infoBean.data = data
        infoBean.callType = callType

        Handler().postDelayed({
            AudioImIn.sendCustomNotification(toUid, Gson().toJson(infoBean),
                object : IMSendCustomNotificationResultCallBack {
                    override fun onException(throwable: Throwable) {
//                        writeAgoraLog("云信发送通话邀请异常${throwable.message}-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}", "confide.log", true)
//                        LogHelper.getInstance().uploadLog(false)
                        AliYunRichLogsHelper.getInstance().sendRichLog(
                            AliYunLogConfig.YUNXIN,
                            "云信发送通话邀请异常${throwable.message}"
                        )
                    }

                    override fun onFailed(code: Int) {
//                        writeAgoraLog("云信发送通话邀请失败${code}-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}", "confide.log", true)
//                        LogHelper.getInstance().uploadLog(false)
                        AliYunRichLogsHelper.getInstance().sendRichLog(
                            AliYunLogConfig.YUNXIN,
                            "云信发送通话邀请失败${code}"
                        )
                    }

                    override fun onSuccess() {
                        writeAgoraLog(
                            "云信发送通话邀请成功-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}",
                            "confide.log",
                            true
                        )
                        AliYunRichLogsHelper.getInstance().sendRichLog(
                            AliYunLogConfig.YUNXIN,
                            "云信发送通话邀请成功"
                        )
                    }
                })
        }, 300)

    }

    fun login(userId: String?) {
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this)
        }
        login(userId) { _, _ ->
        }
    }

    @SuppressLint("CheckResult")
    fun login(userId: String?, event: (isSuccess: Boolean, msg: String?) -> Unit) {
        if (TextUtils.isEmpty(userId) || (userId ?: "0") <= "0") {
            //如果uid为空或小于等于0 ，则不进行登录，因为uid为0也会登录成功，会导致后面uid正确时无法登录
            LogUtil.e("[agora]login-uid:$userId")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "uid为空或小于等于0 ，则不进行登录 login-uid:$userId")
            return
        }
        isOnlineRtm = true
        //登录实时消息
        //获取token
        AudioApiRequestUtil.getAgoraToken().subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread()).subscribe({
                if ("200" == it.code) {
                    LogUtil.e("[agora]登录av的login-uid:$userId")
                    AudioApiRequestUtil.reportCallEvent(YDLVoiceManager.currentChannel, IMEvent(IMEvent.Event.rtmLogin))
                    YDLRTMClient.instances.login(
                        LoginParam(userId, it.data.token),
                        object : LoginCallback {
                            override fun onSuccess() {
                                //登陆成功，发起呼叫
                                AudioApiRequestUtil.reportCallEvent(YDLVoiceManager.currentChannel, IMEvent(IMEvent.Event.loginSuccess))
                                LogUtil.e("[agora]实时消息登录成功")
                                AliYunRichLogsHelper.getInstance()
                                    .sendRichLog(AliYunLogConfig.AGORA, "声网rtm登录成功，uid:$userId")
                                writeAgoraLog(
                                    "声网rtm登录成功,uid:$userId-------Time:${
                                        AudioLogUtils.format.format(
                                            Calendar.getInstance().time
                                        )
                                    }", "confide.log", true
                                )
                                event(true, "")
                            }

                            override fun onFailure(msg: String?) {
                                if (msg != "LOGIN_ERR_ALREADY_LOGGED_IN") {
                                    Apm.reportEvent("rtm_android", "connectionstate_error", msg ?: "")

                                    AudioApiRequestUtil.reportCallEvent(YDLVoiceManager.currentChannel, IMEvent(IMEvent.Event.loginFail), errorReason = msg)
                                }
                                LogUtil.e("[agora]实时消息登录失败：$msg")
                                writeAgoraLog(
                                    "声网rtm登录失败:$msg-------Time:${
                                        AudioLogUtils.format.format(
                                            Calendar.getInstance().time
                                        )
                                    }", "confide.log", true
                                )
                                AliYunRichLogsHelper.getInstance()
                                    .sendRichLog(AliYunLogConfig.AGORA, "声网rtm登录失败:$msg")

                                event(false, msg)
                            }
                        })
                } else {
                    Apm.reportEvent("rtm_android", "login_failure", "${it.code},${it.msg}")
                    LogUtil.e("声网token获取失败uid:" + userId + " error:" + it.msg)
                    LogHelper.getInstance()
                        .writeLogSync("声网token获取失败uid:" + userId + " error:" + it.msg)
                    AliYunRichLogsHelper.getInstance().sendRichLog(
                        AliYunLogConfig.AGORA,
                        "声网token获取失败uid" + userId + " error:" + it.msg
                    )

                }
            }, {
                LogUtil.e("声网token获取异常uid:" + userId + " error:" + it.message)
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "声网token获取异常uid:" + userId + " error:" + it.message
                )

            })
    }

    /**
     * 收到邀请
     */
    @SuppressLint("CheckResult")
    fun receivedCall(content: String?, from: String = "") {
        if (!TextUtils.isEmpty(content)) {
            //如果已经接听了用户电话 再有电话进来 是不能接听的
            if (!activityIsExists(ConsultantAudioHomeActivity::class.java) && !activityIsExists(
                    AudioHomeActivity::class.java
                )
            ) {
                //延时启动通话界面，防止刚打开就被main遮挡
                Observable.timer(1000, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread()).subscribe {
                        LogUtil.e("[agora]启动通话界面")
                        writeAgoraLog(
                            "收到主叫方通话邀请($from)-------Time:${
                                AudioLogUtils.format.format(
                                    Calendar.getInstance().time
                                )
                            }", FILE_NAME, false
                        )
                        AliYunRichLogsHelper.getInstance()
                            .sendRichLog(AliYunLogConfig.AGORA, "收到主叫方通话邀请($from)")

                        LogHelper.getInstance().uploadLog(false)
                        //邀请加入频道消息，跳转通话界面
                        ARouter.getInstance().build("/av/ConsultantAudioHomeActivity")
                            .withString("param", content).navigation()
                    }
            } else {
                LogUtil.d("[agora]收到声网邀请，但界面实例已存在")
                writeAgoraLog(
                    "收到主叫方通话邀请，但界面实例已存在($from)-------Time:${
                        AudioLogUtils.format.format(
                            Calendar.getInstance().time
                        )
                    }", FILE_NAME, false
                )

                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "收到主叫方通话邀请，但界面实例已存在($from)")
                LogHelper.getInstance().uploadLog(false)
            }
        } else {
            LogUtil.d("[agora]收到声网邀请，但response==null")
            writeAgoraLog(
                "收到主叫方通话邀请，但response==null($from)-------Time:${
                    AudioLogUtils.format.format(
                        Calendar.getInstance().time
                    )
                }", FILE_NAME, false
            )
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "收到主叫方通话邀请，但response==null($from)")
            LogHelper.getInstance().uploadLog(false)
        }
    }

    private fun activityIsExists(cls: Class<*>): Boolean {
        for (activity in ActivityManager.getInstance().getActivitys()) {
            if (activity.javaClass == cls) {
                return true
            }
        }
        return false
    }

    /**
     * 关闭通话界面
     */
    fun closePage() {
        var act = ActivityManager.getInstance().getTopTaskActivity()
        if (act is ConsultantAudioHomeActivity) {
            //未接通时，收到呼叫进程失败关闭页面，已接通无需关闭
            if (act.status == ConsultantAudioHomeActivity.STATUS_NOT_ANSWERED) {
                act.close(ConsultantAudioHomeActivity.RESULT_USER_CANCEL, "")
            }
        }
    }

    /**
     * 退出登录
     * @param
     */
    private fun logout(isReLogin: Boolean) {
        EventBus.getDefault().unregister(this)
        AudioApiRequestUtil.reportCallEvent(YDLVoiceManager.currentChannel, IMEvent(IMEvent.Event.rtmLogout))
        YDLRTMClient.instances.logout(object : LoginCallback {
            override fun onSuccess() {
                //退出登陆成功
                LogUtil.d("[agora]实时消息退出成功")
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "实时消息退出成功")
                if (isReLogin) {
                    login(
                        ModularServiceManager.provide(IUserService::class.java).getUserInfo()?.uid
                    )
                }
            }

            override fun onFailure(msg: String?) {
                LogUtil.d("[agora]实时消息退出失败：$msg")
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "实时消息退出失败：$msg")
            }
        })
    }

    /**
     * 退出登录默认不重新登录
     */
    fun logout() {
        logout(false)
    }

    /**
     * RTM登录异常，上传错误日志 msg
     * 声网出现异常，上传错误日志 connectException
     */
    @SuppressLint("CheckResult")
    fun uploadException(
        connectException: ConnectExceptionCommand,
        callback: UploadExceptionCallback?
    ) {
        AudioApiRequestUtil.connectException(connectException).subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread()).subscribe({
                callback?.onSuccess()
            }, {
                LogUtil.e("agora", "声网上传异常与错误日志接口调用失败:" + it.message)
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "声网上传异常与错误日志接口调用失败: + ${it.message}")
            })
    }

    /**
     * 上传异常错误回调
     */
    interface UploadExceptionCallback {
        fun onSuccess()
    }


    @SuppressLint("CheckResult")
    fun callEndStatusUpdate(channelId: String?, endStatus: Int, msg: String) {
        if (channelId == null) return
        AudioApiRequestUtil.callEventSave(channelId, "7", endStatus.toString(), null, msg)
            .subscribeOn(Schedulers.io())
            .subscribe()
    }

    /**
     * 实时消息全局监听
     */
    private val listener = object : InitListener {

        override fun onTokenExpired() {
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "onTokenExpired")
            LogUtil.e("[agora]onTokenExpired")
            instances.login(
                ModularServiceManager.provide(IUserService::class.java).getUserInfo()?.uid
            )
        }

        override fun onMessageReceived(message: RTMMesssage, userId: Int) {
            LogUtil.i("[agora]onMessageReceived:${message.text} -->uid:$userId")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(
                    AliYunLogConfig.AGORA,
                    "onMessageReceived:${message.text} -->uid:$userId"
                )
        }
        /**
         * https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler.html#a31b2974a574ec45e62bb768e17d1f49e
         * */
        override fun onConnectionStateChanged(state: Int, reason: Int) {
            val msg = "state:${state},reason:${reason}"
            VLog.i(TAG, msg)
            sdkStatus = state
            writeAgoraLog(
                "声网rtm登录状态：${state}-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}",
                "confide.log",
                true
            )
            LogUtil.i("[agora]onConnectionStateChanged:state:${state} -->reason:$reason")
            AudioApiRequestUtil.reportCallEvent(
                YDLVoiceManager.currentChannel,
                IMEvent(IMEvent.Event.onlineStatusChange),
                errorCode = state,
                errorReason = reason.toString()
            )
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "声网rtm登录状态：${state}")
            /*
            * 当reason=CONNECTION_CHANGE_REASON_REMOTE_LOGIN的时候，是远端用户以相同UID登录RTM
            * 如果正在通话中，则不进行退出操作
            * */
            if (reason == CONNECTION_CHANGE_REASON_REMOTE_LOGIN) {
                if (!activityIsExists(ConsultantAudioHomeActivity::class.java) &&
                    !activityIsExists(AudioHomeActivity::class.java)) {
                    isOnlineRtm = false
                    logout()
                } else {
                    logout(true)
                }
            }
        }
    }

    /**
     *  倾诉日志
     * @param session 通话业务id
     * @param status 状态:01通话中(不影响通话的事件) 10:拨打 20未拨通 30未接通 40 接通 50挂断 60断线 70重连 80 呼叫方信号 90 被呼叫方信号
     * @param res 上报的详细
     * @param line 载体:1.网易 2.中国移动(双呼)3.联通 4.华为 5.糖猫-联通 7:声网 8:微信 10:新移动
     * */
    fun callEventSave(
        status: String,
        res: String,
        session: String?,
        line: String
    ) {
        //保证session有值
       session?.let { sessionLet ->
           AudioApiRequestUtil.callEventSave(sessionLet, line, status, "用户端：${res}")
               .subscribeOn(Schedulers.io())
               .observeOn(AndroidSchedulers.mainThread())
               .subscribe()
       }

    }
}