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.google.gson.Gson
import com.ydl.audioim.bean.AgoraInvitationBean
import com.ydl.audioim.http.AudioApiRequestUtil
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.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.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.common.tools.ToastUtil
import com.yidianling.im.api.bean.IMRegisterObserverCustomNotificationCallBack
import com.yidianling.im.api.bean.IMSendCustomNotificationResultCallBack
import com.yidianling.user.api.event.UserLoginEvent
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"

        //当前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"//音频权限未通过错误码
    }


    fun init(context: Context, appId: String) {
        YDLRTMClient.instances.init(context, appId, listener)
        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: UserLoginEvent) {
        instances.login(event.uid)
    }

    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}"
                )

                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}已接收呼叫邀请"
                )
                //加入声网频道时机修改：主叫收到被叫接受邀请的回调后再加入声网频道
                val act = ActivityManager.getInstance().getTopTaskActivity()
                if (act is AudioHomeActivity) {
                    act.runOnUiThread {
                        act.joinChannel()
                    }
                }
            }

            override fun onCallRefused(response: CallLocalResponse?, msg: String?) {
                //返回给主叫
                LogUtil.e("[agora]${response?.calleeId}已拒绝呼叫邀请")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "${response?.calleeId}已拒绝呼叫邀请"
                )
                val act = ActivityManager.getInstance().getTopTaskActivity()
                if (act is AudioHomeActivity) {
                    act.runOnUiThread {
                        callEndStatusUpdate(response?.ChannelId!!, 2, "被叫拒绝")
                        ToastUtil.toastShort("对方已挂断")
                        act.writeAgoraLog("被叫（专家）拒绝了通话邀请")
                        //通话结束或挂断时，上传日志文件
                        act.uploadLog()
                        act.leaveChannel()
                        act.uploadExceptionStatus("对方已拒绝", 2)
                    }
                }
            }

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

            override fun onCallFailure(response: CallLocalResponse?, errorCode: Int) {
                //返回给主叫
                LogUtil.e("[agora]呼叫${response?.calleeId}用户失败：${response?.response}")
                AliYunRichLogsHelper.getInstance().sendRichLog(
                    AliYunLogConfig.AGORA,
                    "呼叫${response?.calleeId}用户失败：${response?.response}"
                )
                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!!, 2, "超时未接听导致的取消呼叫")
                //关闭页面
                closePage()
            }

            override fun onOtherMsg(error: String?) {
                LogUtil.e("[agora]其它消息：${error}")
                if (error.equals("呼叫发送成功")) {
                    writeAgoraLog(
                        "声网发送通话邀请成功-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}",
                        "confide.log",
                        true
                    )
                    AliYunRichLogsHelper.getInstance().sendRichLog(
                        AliYunLogConfig.AGORA,
                        "声网发送通话邀请成功"
                    )
                } else {
                    writeAgoraLog(
                        "声网发送通话邀请失败${error}-------Time:${
                            AudioLogUtils.format.format(
                                Calendar.getInstance().time
                            )
                        }", "confide.log", true
                    )
                    LogHelper.getInstance().uploadLog(false)
                    AliYunRichLogsHelper.getInstance().sendRichLog(
                        AliYunLogConfig.AGORA,
                        "声网发送通话邀请失败${error}"
                    )
                }
            }
        })

        AudioImIn.registerObserveCustomNotification(object :
            IMRegisterObserverCustomNotificationCallBack {
            override fun onObserverCustomNotification(
                fromUid: String,
                toUid: String,
                content: String
            ) {


//                LogUtil.e("[agora]收到云信的通知消息：$content")
//                val agoraInvitationBean = Gson().fromJson(content, AgoraInvitationBean::class.java)

                //1发起呼叫 2接受呼叫  3取消呼叫  4拒绝呼叫邀请 5呼叫超时
//                when (agoraInvitationBean.callType) {
//                    "1" -> {
//                        writeAgoraLog("1收到云信消息通知电话-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}", FILE_NAME)
//                        receivedCall(agoraInvitationBean.data, "来自云信")
//                    }
//                    "2" -> {
//                        writeAgoraLog("对方接受了通话邀请，主叫开始加入频道：callType${agoraInvitationBean.callType}-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}",
//                            FILE_NAME
//                        )
//                        val act = ActivityManager.getInstance().getTopTaskActivity()
//                        if (act is AudioHomeActivity) {
//                            act.runOnUiThread {
//                                act.joinChannel()
//                            }
//                        }
//                    }
//                    "3" -> {
//                        writeAgoraLog("呼叫邀请被取消：主叫主动取消-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}", FILE_NAME)
//                        closePage()
//                    }
//                    "4" -> {
//                        writeAgoraLog("被叫拒绝了通话邀请-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}", FILE_NAME)
//                        val act = ActivityManager.getInstance().getTopTaskActivity()
//                        if (act is AudioHomeActivity) {
//                            act.runOnUiThread {
//                                ToastUtil.toastShort("对方已挂断")
//                                //通话结束或挂断时，上传日志文件
//                                act.uploadLog()
//                                act.leaveChannel()
//                            }
//                        }
//                    }
//                    "5" -> {
//                        writeAgoraLog("呼叫邀请被取消：呼叫邀请过期-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}", FILE_NAME)
//                        //关闭页面
//                        closePage()
//                    }
//                    else -> {
//                        writeAgoraLog("其它AgoraInvitationBean,${agoraInvitationBean.callType}-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}", FILE_NAME)
//                    }
//                }
            }
        })
    }

    fun rtcCall(listenerUid: String?, channelId: String?, sendDoctocrMsg: String?) {
        YDLRTMClient.instances.call(listenerUid, channelId, sendDoctocrMsg)

        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, "主叫取消呼叫")
        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?) {
        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")
                    YDLRTMClient.instances.login(
                        LoginParam(userId, it.data.token),
                        object : LoginCallback {
                            override fun onSuccess() {
                                //登陆成功，发起呼叫
                                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?) {
                                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 {
                    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)
        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) {
        AudioApiRequestUtil.callEndStatusUpdate(channelId, endStatus, msg)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({
            }, {
                LogUtil.d("callEndStatusUpdate error: ${it.message}")

                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "callEndStatusUpdate error: ${it.message}")
            })
    }

    /**
     * 实时消息全局监听
     */
    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")
        }

        override fun onConnectionStateChanged(state: Int, reason: Int) {
            sdkStatus = state
            writeAgoraLog(
                "声网rtm登录状态：${state}-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}",
                "confide.log",
                true
            )
            LogUtil.i("[agora]onConnectionStateChanged:state:${state} -->reason:$reason")
            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)
                }
            }
        }
    }
}