package com.adealink.frame.imkit

import android.app.Application
import android.text.TextUtils
import com.adealink.frame.data.json.toJsonErrorNull
import com.adealink.frame.imkit.config.IIMConfig
import com.adealink.frame.imkit.config.MessageInterceptor
import com.adealink.frame.imkit.event.actionevent.ClearEvent
import com.adealink.frame.imkit.event.actionevent.DeleteEvent
import com.adealink.frame.imkit.event.actionevent.InsertEvent
import com.adealink.frame.imkit.event.actionevent.MessageEventListener
import com.adealink.frame.imkit.event.actionevent.RecallEvent
import com.adealink.frame.imkit.event.actionevent.RefreshEvent
import com.adealink.frame.imkit.event.actionevent.SendEvent
import com.adealink.frame.imkit.event.actionevent.SendMediaEvent
import com.adealink.frame.imkit.listener.ConversationEventListener
import com.adealink.frame.imkit.manager.UnReadMessageManager
import com.adealink.frame.imkit.model.KEY_APP_BASE_INFO
import com.adealink.frame.imkit.model.SendMessageExtra
import com.adealink.frame.imkit.model.TAG_IM_MSG_BLOCK
import com.adealink.frame.imkit.model.TAG_IM_MSG_EXPANSION
import com.adealink.frame.imkit.model.TAG_IM_SERVICE
import com.adealink.frame.imkit.resend.ResendManager
import com.adealink.frame.imkit.utils.ExecutorHelper
import com.adealink.frame.log.Log
import com.adealink.frame.util.AppUtil
import io.rong.common.SystemUtils
import io.rong.imlib.ChannelClient
import io.rong.imlib.IRongCallback
import io.rong.imlib.IRongCoreCallback
import io.rong.imlib.IRongCoreEnum
import io.rong.imlib.IRongCoreEnum.CoreErrorCode
import io.rong.imlib.IRongCoreListener
import io.rong.imlib.MessageTag
import io.rong.imlib.RongCoreClient
import io.rong.imlib.RongIMClient
import io.rong.imlib.common.ExecutorFactory
import io.rong.imlib.listener.OnReceiveMessageWrapperListener
import io.rong.imlib.model.ConnectOption
import io.rong.imlib.model.Conversation
import io.rong.imlib.model.Conversation.ConversationType
import io.rong.imlib.model.ConversationIdentifier
import io.rong.imlib.model.ConversationStatus
import io.rong.imlib.model.HistoryMessageOption
import io.rong.imlib.model.InitOption
import io.rong.imlib.model.Message
import io.rong.imlib.model.Message.ReceivedStatus
import io.rong.imlib.model.Message.SentStatus
import io.rong.imlib.model.MessageContent
import io.rong.imlib.model.ReceivedProfile
import io.rong.imlib.model.SendMessageOption
import io.rong.imlib.model.TagInfo
import io.rong.message.ReadReceiptMessage
import io.rong.message.RecallNotificationMessage
import io.rong.message.SightMessage
import kotlinx.coroutines.launch
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.coroutines.resume

class IMService(val config: IIMConfig) {

    companion object {

        lateinit var innerService: IMService

        @Synchronized
        fun create(config: IIMConfig): IMService {
            return IMService(config).apply { innerService = this }
        }
    }

    private var isInit: Boolean = false
    private var offlineMessageSyncCompleted: Boolean = false
    private var messageInterceptor: MessageInterceptor? = null

    private val connectStatusListener = CopyOnWriteArrayList<IRongCoreCallback.ConnectCallback>()
    private val connectionStatusObserverList = CopyOnWriteArrayList<RongIMClient.ConnectionStatusListener>()
    private val onReceiveMessageObserverList = CopyOnWriteArrayList<IRongCoreListener.OnReceiveMessageWrapperListener>()
    private val asyncOnReceiveMessageObserverList = CopyOnWriteArrayList<IRongCoreListener.OnReceiveMessageWrapperListener>()
    private val conversationStatusObserverList = CopyOnWriteArrayList<RongIMClient.ConversationStatusListener>()
    private val conversationEventListener = CopyOnWriteArrayList<ConversationEventListener>()
    private val messageEventListeners = CopyOnWriteArrayList<MessageEventListener>()
    private val onRecallMessageObserverList = CopyOnWriteArrayList<RongIMClient.OnRecallMessageListener>()
    private val readReceiptObserverList = CopyOnWriteArrayList<RongIMClient.ReadReceiptListener>()
    private val syncConversationReadStatusListeners = CopyOnWriteArrayList<RongIMClient.SyncConversationReadStatusListener>()
    private val cancelSendMediaMessageListeners = CopyOnWriteArrayList<RongIMClient.ResultCallback<Message>>()
    private val messageBlockListeners = CopyOnWriteArrayList<IRongCoreListener.MessageBlockListener>()
    private val messageExpansionListeners = CopyOnWriteArrayList<RongIMClient.MessageExpansionListener>()

    /** 连接状态变化的监听器。  */
    private val connectionStatusListener =
        IRongCoreListener.ConnectionStatusListener { connectionStatus ->
            for (listener in connectionStatusObserverList) {
                listener.onChanged(
                    RongIMClient.ConnectionStatusListener.ConnectionStatus.valueOf(
                        connectionStatus.value
                    )
                )
            }
        }

    /** 接受消息的事件监听器。  */
    private val onReceiveMessageListener: OnReceiveMessageWrapperListener =
        object : OnReceiveMessageWrapperListener() {
            override fun onReceivedMessage(message: Message?, profile: ReceivedProfile?) {
                if (message == null || profile == null) {
                    return
                }
                if (messageInterceptor != null
                    && messageInterceptor?.interceptReceivedMessage(
                        message,
                        profile.left,
                        profile.hasPackage(),
                        profile.isOffline
                    ) == true
                ) {
                    Log.d(TAG_IM_SERVICE, "message has been intercepted.")
                    return
                }

                dispatchOnReceiveMessageObserver(message, profile)

                for (observer in asyncOnReceiveMessageObserverList) {
                    observer.onReceived(
                        message,
                        profile.left,
                        profile.hasPackage(),
                        profile.isOffline
                    )
                }
            }

            override fun onOfflineMessageSyncCompleted() {
                super.onOfflineMessageSyncCompleted()
                offlineMessageSyncCompleted = true
                dispatchOnOfflineMessageSyncCompleted()
            }
        }

    /** 会话状态监听器。当会话的置顶或者免打扰状态更改时，会回调此方法。  */
    private val conversationStatusListener =
        RongIMClient.ConversationStatusListener { conversationStatuses ->
            for (listener in conversationStatusObserverList) {
                listener.onStatusChanged(conversationStatuses)
            }
        }

    /** 消息被撤回时的监听器。  */
    private val onRecallMessageListener =
        RongIMClient.OnRecallMessageListener { message, recallNotificationMessage ->
            for (listener in onRecallMessageObserverList) {
                listener.onMessageRecalled(message, recallNotificationMessage)
            }
            false
        }

    /** 消息回执监听器  */
    private val readReceiptListener: RongIMClient.ReadReceiptListener =
        object : RongIMClient.ReadReceiptListener {
            /**
             * 单聊中收到消息回执的回调。
             *
             * @param message 封装了 [ReadReceiptMessage]
             */
            override fun onReadReceiptReceived(message: Message?) {
                ExecutorHelper.getInstance()
                    .mainThread()
                    .execute {
                        for (listener in readReceiptObserverList) {
                            listener.onReadReceiptReceived(message)
                        }
                    }
            }

            /**
             * 群组和讨论组中，某人发起了回执请求，会话中其余人会收到该请求，并回调此方法。
             *
             *
             * 接收方需要在合适的时机（读取了消息之后）调用 [ ][RongIMClient.sendReadReceiptResponse] 回复响应。
             *
             * @param conversationType 会话类型
             * @param targetId 会话目标 id
             * @param messageUId 请求已读回执的消息 uId
             */
            override fun onMessageReceiptRequest(
                conversationType: Conversation.ConversationType?,
                targetId: String?,
                messageUId: String?
            ) {

            }

            /**
             * 在群组和讨论组中发起了回执请求的用户，当收到接收方的响应时，会回调此方法。
             *
             * @param conversationType 会话类型
             * @param targetId 会话 id
             * @param messageUId 收到回执响应的消息的 uId
             * @param respondUserIdList 会话中响应了此消息的用户列表。其中 key： 用户 id ； value： 响应时间。
             */
            override fun onMessageReceiptResponse(
                conversationType: Conversation.ConversationType?,
                targetId: String?,
                messageUId: String?,
                respondUserIdList: HashMap<String, Long>?
            ) {

            }
        }

    /**
     * 监听会话已读状态的同步事件
     */
    private val syncConversationReadStatusListener =
        RongIMClient.SyncConversationReadStatusListener { type, targetId ->
            for (item in syncConversationReadStatusListeners) {
                item.onSyncConversationReadStatus(type, targetId)
            }
        }

    /**
     * 敏感信息拦截监听器
     */
    private val messageBlockListener: IRongCoreListener.MessageBlockListener =
        IRongCoreListener.MessageBlockListener { info ->
            Log.e(TAG_IM_MSG_BLOCK, "$info")
            for (item in messageBlockListeners) {
                item.onMessageBlock(info)
            }
        }

    /**
     * 消息拓展更新监听器
     */
    private val messageExpansionListener: RongIMClient.MessageExpansionListener =
        object : RongIMClient.MessageExpansionListener {
            override fun onMessageExpansionUpdate(
                expansion: Map<String, String>?,
                message: Message?
            ) {
                Log.d(
                    TAG_IM_MSG_EXPANSION,
                    "onMessageExpansionUpdate, expansion:$expansion, messageId:${message?.messageId}"
                )
                for (item in messageExpansionListeners) {
                    item.onMessageExpansionUpdate(expansion, message)
                }
            }

            override fun onMessageExpansionRemove(
                keyArray: MutableList<String>?,
                message: Message?
            ) {
                Log.d(
                    TAG_IM_MSG_EXPANSION,
                    "onMessageExpansionRemove, removeKeyArray:$keyArray, messageId:${message?.messageId}"
                )
                for (item in messageExpansionListeners) {
                    item.onMessageExpansionRemove(keyArray, message)
                }
            }

        }

    /**
     * 初始化 SDK，在整个应用程序全局，只需要调用一次。
     *
     * @param application 应用上下文。
     * @param appKey 在融云开发者后台注册的应用 AppKey。
     * @param option 初始化所需要的配置信息，详情可参考 [InitOption]
     * @since 5.4.1
     */
    fun init(application: Application?, option: InitOption?) {
        var opt = option
        if (application == null) {
            Log.e(TAG_IM_SERVICE, "init error: application is null")
            return
        }
        if (TextUtils.isEmpty(config.appKey)) {
            Log.e(TAG_IM_SERVICE, "init error: appKey is null")
            return
        }
        if (option == null) {
            Log.d(TAG_IM_SERVICE, "init warn: option is null")
            opt = InitOption.Builder().build()
        }
        isInit = true
        //开启单进程
        RongCoreClient.getInstance().enableSingleProcess(true)
        RongCoreClient.init(application.applicationContext, config.appKey, opt)
        if (option?.isMainProcess == null) {
            val current = SystemUtils.getCurrentProcessName(application)
            val mainProcessName = application.packageName
            if (mainProcessName != current) {
                Log.d(TAG_IM_SERVICE, "Init. Current process : $current")
                return
            }
        } else if (option.isMainProcess == false) {
            Log.d(TAG_IM_SERVICE, "Init. isMainProcess : Boolean.FALSE")
            return
        }
        RongCoreClient.addOnReceiveMessageListener(onReceiveMessageListener)
        RongCoreClient.addConnectionStatusListener(connectionStatusListener)
        RongIMClient.setOnRecallMessageListener(onRecallMessageListener)
        RongIMClient.getInstance().setConversationStatusListener(conversationStatusListener)
        RongIMClient.setReadReceiptListener(readReceiptListener)
        RongIMClient.getInstance()
            .setSyncConversationReadStatusListener(syncConversationReadStatusListener)
        RongIMClient.getInstance().setMessageBlockListener(messageBlockListener)
        RongIMClient.getInstance().setMessageExpansionListener(messageExpansionListener)
    }

    /**
     * 建立连接前，注册自定义消息，否则sdk无法识别
     */
    fun registerMessageType(messageContentClassList: List<Class<out MessageContent>>) {
        RongIMClient.registerMessageType(messageContentClassList)
    }

    /**
     * 连接服务器，在整个应用程序全局，只需要调用一次。
     *
     *
     * 调用该接口，SDK 会在 timeLimit 秒内尝试重连，直到出现下面三种情况之一： 第一、连接成功，回调 onSuccess(userId)。 第二、超时，回调
     * onError(RC_CONNECT_TIMEOUT)，并不再重连。 第三、出现 SDK 无法处理的错误，回调 onError(errorCode)（如 token 非法），并不再重连。
     * 连接成功后，SDK 将接管所有的重连处理。当因为网络原因断线的情况下，SDK 会不停重连直到连接成功为止，不需要您做额外的连接操作。
     *
     * @param token 从服务端获取的 [用户身份令牌（ Token）](http://docs.rongcloud.cn/android#token)。
     * @param timeLimit 连接超时时间，单位：秒。`timeLimit <= 0`，则 IM 将一直连接，直到连接成功或者无法连接（如 `token`
     * 非法） `timeLimit > 0` ,则 IM 将最多连接 timeLimit 秒： 如果在 timeLimit
     * 秒内连接成功，后面再发生了网络变化或前后台切换，SDK 会自动重连； 如果在 timeLimit 秒无法连接成功则不再进行重连，通过 onError
     * 告知连接超时，您需要再自行调用 connect 接口
     * @param connectCallback 连接服务器的回调扩展类，新增打开数据库的回调，用户可以在此回调中执行拉取会话列表操作。
     * 该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun connect(
        token: String?, timeLimit: Int, connectCallback: IRongCoreCallback.ConnectCallback? = null
    ) {
        val connectOption = ConnectOption.obtain(token, timeLimit)
        connect(connectOption, connectCallback)
    }

    /**
     * 返回 SDK 是否已经初始化。
     *
     * @return true 代表已经初始化；false 未初始化。
     */
    fun isInitialized(): Boolean {
        return isInit
    }


    /**
     * 获取融云日志目录
     * 路径格式：/data/data/app包名/files/appkey/rclog
     */
    fun getRongCloudLogDir(): String {
        val filesDir = AppUtil.appContext.filesDir.absolutePath
        val appKey = config.appKey
        return "$filesDir/$appKey/rclog"
    }

    /**
     * 离线消息是否收取完毕
     */
    fun offlineMessageSyncCompleted(): Boolean {
        return offlineMessageSyncCompleted
    }

    private fun connect(option: ConnectOption, connectCallback: IRongCoreCallback.ConnectCallback?) {
        RongCoreClient.connect(
            option.token,
            option.timeLimit,
            config.userId,
            object : IRongCoreCallback.ConnectCallback() {
                override fun onSuccess(s: String?) {
                    connectCallback?.onSuccess(s)
                    if (!TextUtils.isEmpty(s)) {
                        for (callback in connectStatusListener) {
                            callback.onSuccess(s)
                        }
                    } else {
                        Log.e(TAG_IM_SERVICE, "IM connect success but userId is empty.")
                    }
                }

                override fun onError(connectionErrorCode: IRongCoreEnum.ConnectionErrorCode?) {
                    connectCallback?.onError(connectionErrorCode)
                    for (callback in connectStatusListener) {
                        callback.onError(connectionErrorCode)
                    }
                }

                override fun onDatabaseOpened(databaseOpenStatus: IRongCoreEnum.DatabaseOpenStatus?) {
                    connectCallback?.onDatabaseOpened(databaseOpenStatus)
                    for (callback in connectStatusListener) {
                        callback.onDatabaseOpened(databaseOpenStatus)
                    }
                }
            })
    }

    /** 断开连接 */
    fun disconnect() {
        RongIMClient.getInstance().disconnect()
    }

    /** 注销当前登录 */
    fun logout() {
        RongIMClient.getInstance().logout()
    }

    private fun dispatchOnReceiveMessageObserver(message: Message, profile: ReceivedProfile) {
        if (onReceiveMessageObserverList.isEmpty()) {
            return
        }
        if (!ExecutorFactory.isMainThread()) {
            ExecutorFactory.getInstance()
                .mainHandler
                .post { dispatchOnReceiveMessageObserver(message, profile) }
            return
        }

        for (observer in onReceiveMessageObserverList) {
            observer.onReceived(
                message, profile.left, profile.hasPackage(), profile.isOffline
            )
        }
    }

    private fun dispatchOnOfflineMessageSyncCompleted() {
        if (onReceiveMessageObserverList.isEmpty()) {
            return
        }
        if (!ExecutorFactory.isMainThread()) {
            ExecutorFactory.getInstance()
                .mainHandler
                .post { dispatchOnOfflineMessageSyncCompleted() }
            return
        }
        for (observer in onReceiveMessageObserverList) {
            observer.onOfflineMessageSyncCompleted()
        }
    }

    fun getCurrentConnectionStatus(): RongIMClient.ConnectionStatusListener.ConnectionStatus {
        return RongIMClient.getInstance().currentConnectionStatus
    }

    /**
     * 设置连接状态变化的监听器。
     *
     * <p><strong> 当回调状态为{@link
     * RongIMClient.ConnectionStatusListener.ConnectionStatus#TOKEN_INCORRECT}, 需要获取正确的token,
     * 并主动调用{@link RongIM#connect(String, int, RongIMClient.ConnectCallback)} </strong>
     *
     * @param listener 连接状态变化的监听器。
     */
    fun addConnectionStatusListener(listener: RongIMClient.ConnectionStatusListener) {
        if (connectionStatusObserverList.contains(listener)) {
            return
        }
        connectionStatusObserverList.add(listener)
    }

    /**
     * 移除连接状态监听器
     *
     * @param listener 连接状态变化监听器
     */
    fun removeConnectionStatusListener(listener: RongIMClient.ConnectionStatusListener) {
        connectionStatusObserverList.remove(listener)
    }

    fun addOnReceiveMessageListener(listener: RongIMClient.OnReceiveMessageWrapperListener) {
        if (onReceiveMessageObserverList.contains(listener)) {
            return
        }
        onReceiveMessageObserverList.add(listener)
    }

    fun removeOnReceiveMessageListener(listener: RongIMClient.OnReceiveMessageWrapperListener) {
        onReceiveMessageObserverList.remove(listener)
    }

    fun addAsyncOnReceiveMessageListener(
        listener: RongIMClient.OnReceiveMessageWrapperListener
    ) {
        if (asyncOnReceiveMessageObserverList.contains(listener)) {
            return
        }
        asyncOnReceiveMessageObserverList.add(listener)
    }

    fun removeAsyncOnReceiveMessageListener(
        listener: RongIMClient.OnReceiveMessageWrapperListener
    ) {
        asyncOnReceiveMessageObserverList.remove(listener)
    }

    fun addConversationStatusListener(listener: RongIMClient.ConversationStatusListener) {
        if (conversationStatusObserverList.contains(listener)) {
            return
        }
        conversationStatusObserverList.add(listener)
    }

    fun removeConversationStatusListener(listener: RongIMClient.ConversationStatusListener) {
        conversationStatusObserverList.remove(listener)
    }

    fun addOnRecallMessageListener(listener: RongIMClient.OnRecallMessageListener) {
        if (onRecallMessageObserverList.contains(listener)) {
            return
        }
        onRecallMessageObserverList.add(listener)
    }

    fun removeOnRecallMessageListener(listener: RongIMClient.OnRecallMessageListener) {
        onRecallMessageObserverList.remove(listener)
    }

    fun addReadReceiptListener(listener: RongIMClient.ReadReceiptListener) {
        if (readReceiptObserverList.contains(listener)) {
            return
        }
        readReceiptObserverList.add(listener)
    }

    fun removeReadReceiptListener(listener: RongIMClient.ReadReceiptListener) {
        readReceiptObserverList.remove(listener)
    }

    fun addConnectStatusListener(callback: IRongCoreCallback.ConnectCallback) {
        if (connectStatusListener.contains(callback)) {
            return
        }
        connectStatusListener.add(callback)
    }

    fun removeConnectStatusListener(callback: IRongCoreCallback.ConnectCallback) {
        connectStatusListener.remove(callback)
    }

    fun addSyncConversationReadStatusListener(
        listener: RongIMClient.SyncConversationReadStatusListener
    ) {
        if (syncConversationReadStatusListeners.contains(listener)) {
            return
        }
        syncConversationReadStatusListeners.add(listener)
    }

    fun removeSyncConversationReadStatusListeners(
        listener: RongIMClient.SyncConversationReadStatusListener
    ) {
        syncConversationReadStatusListeners.remove(listener)
    }

    fun addMessageBlockListener(
        listener: IRongCoreListener.MessageBlockListener
    ) {
        if (messageBlockListeners.contains(listener)) {
            return
        }
        messageBlockListeners.add(listener)
    }

    fun removeMessageBlockListener(
        listener: IRongCoreListener.MessageBlockListener
    ) {
        messageBlockListeners.remove(listener)
    }

    fun addMessageExpansionListener(
        listener: RongIMClient.MessageExpansionListener
    ) {
        if (messageExpansionListeners.contains(listener)) {
            return
        }
        messageExpansionListeners.add(listener)
    }

    fun removeMessageExpansionListener(
        listener: RongIMClient.MessageExpansionListener
    ) {
        messageExpansionListeners.remove(listener)
    }

    fun notifyMessageExpansionUpdate(expansion: Map<String, String>?,
                                     message: Message?) {

    }

    fun addConversationEventListener(listener: ConversationEventListener) {
        if (!conversationEventListener.contains(listener)) {
            conversationEventListener.add(listener)
        }
    }

    fun removeConversationEventListener(listener: ConversationEventListener) {
        conversationEventListener.remove(listener)
    }

    fun addMessageEventListener(listener: MessageEventListener) {
        if (messageEventListeners.contains(listener)) {
            return
        }
        messageEventListeners.add(listener)
    }

    fun removeMessageEventListener(listener: MessageEventListener) {
        messageEventListeners.remove(listener)
    }

    fun addCancelSendMediaMessageListener(listener: RongIMClient.ResultCallback<Message>) {
        if (cancelSendMediaMessageListeners.contains(listener)) {
            return
        }
        cancelSendMediaMessageListeners.add(listener)
    }

    fun removeCancelSendMediaMessageListener(
        listener: RongIMClient.ResultCallback<Message>
    ) {
        cancelSendMediaMessageListeners.remove(listener)
    }

    /**
     * 多端同步会话阅读状态。
     *
     * @param type 会话类型
     * @param targetId 会话 id
     * @param timestamp 会话中已读的最后一条消息的发送时间戳 [Message.getSentTime]
     * @param callback 回调函数。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun syncConversationReadStatus(
        type: Conversation.ConversationType,
        targetId: String,
        timestamp: Long,
        callback: RongIMClient.OperationCallback?
    ) {
        syncConversationReadStatus(
            ConversationIdentifier.obtain(type, targetId, ""), timestamp, callback
        )
    }

    /**
     * 多端同步会话阅读状态。
     *
     * @param conversationIdentifier 会话标识
     * @param timestamp 会话中已读的最后一条消息的发送时间戳 [Message.getSentTime]
     * @param callback 回调函数。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun syncConversationReadStatus(
        conversationIdentifier: ConversationIdentifier,
        timestamp: Long,
        callback: RongIMClient.OperationCallback?
    ) {
        ChannelClient.getInstance()
            .syncConversationReadStatus(
                conversationIdentifier.type,
                conversationIdentifier.targetId,
                conversationIdentifier.channelId,
                timestamp,
                object : IRongCoreCallback.OperationCallback() {
                    override fun onSuccess() {
                        callback?.onSuccess()
                        for (listener in conversationEventListener) {
                            listener.onClearedUnreadStatus(conversationIdentifier)
                        }
                    }

                    override fun onError(coreErrorCode: CoreErrorCode) {
                        callback?.onError(
                            RongIMClient.ErrorCode.valueOf(coreErrorCode.code)
                        )
                        for (listener in conversationEventListener) {
                            listener.onClearedUnreadStatus(conversationIdentifier)
                        }
                    }
                })
    }

    /**
     * 设置接收消息时的拦截器
     *
     * @param messageInterceptor 拦截器
     */
    fun setMessageInterceptor(messageInterceptor: MessageInterceptor) {
        this.messageInterceptor = messageInterceptor
    }

    /**
     * 根据会话类型，发送消息。
     *
     *
     * 通过 [IRongCallback.ISendMessageCallback] 中的方法回调发送的消息状态及消息体。<br></br>
     * **注意：1 秒钟发送消息不能超过 5 条**。
     *
     * @param type 会话类型。
     * @param targetId 会话 id。根据不同的 conversationType，可能是用户 id、讨论组 id、群组 id 或聊天室 id。
     * @param content 消息内容，例如 [TextMessage], [ImageMessage]。
     * @param pushContent 当下发远程推送消息时，在通知栏里会显示这个字段。 如果发送的是自定义消息，该字段必须填写，否则无法收到远程推送消息。 如果发送 SDK
     * 中默认的消息类型，例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg，则不需要填写，默认已经指定。
     * @param pushData 远程推送附加信息。如果设置该字段，用户在收到 push 消息时，能通过 [     ][io.rong.push.notification.PushNotificationMessage.getPushData] 方法获取。
     * @param callback 发送消息的回调。参考 [IRongCallback.ISendMessageCallback]。
     * 该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun sendMessage(
        type: Conversation.ConversationType,
        targetId: String,
        content: MessageContent,
        pushContent: String? = null,
        pushData: String? = null,
        callback: IRongCallback.ISendMessageCallback?
    ) {
        val message = Message.obtain(targetId, type, content)
        sendMessage(message, pushContent, pushData, callback)
    }

    /**
     * 发送消息。 通过 [IRongCallback.ISendMessageCallback] 中的方法回调发送的消息状态及消息体。
     *
     * @param message 将要发送的消息体。
     * @param pushContent 当下发 push 消息时，在通知栏里会显示这个字段。 如果发送的是自定义消息，该字段必须填写，否则无法收到 push 消息。 如果发送 sdk
     * 中默认的消息类型，例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg，则不需要填写，默认已经指定。
     * @param pushData push 附加信息。如果设置该字段，用户在收到 push 消息时，能通过 [     ][io.rong.push.notification.PushNotificationMessage.getPushData] 方法获取。
     * @param callback 发送消息的回调，参考 [IRongCallback.ISendMessageCallback]。
     * 该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun sendMessage(
        message: Message,
        pushContent: String? = null,
        pushData: String? = null,
        callback: IRongCallback.ISendMessageCallback?
    ) {
        sendMessage(message, pushContent, pushData, null, callback)
    }

    /**
     * 发送消息。 通过 [IRongCallback.ISendMessageCallback] 中的方法回调发送的消息状态及消息体。
     *
     * @param message 将要发送的消息体。
     * @param pushContent 当下发 push 消息时，在通知栏里会显示这个字段。 如果发送的是自定义消息，该字段必须填写，否则无法收到 push 消息。 如果发送 sdk
     * 中默认的消息类型，例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg，则不需要填写，默认已经指定。
     * @param pushData push 附加信息。如果设置该字段，用户在收到 push 消息时，能通过 [     ][io.rong.push.notification.PushNotificationMessage.getPushData] 方法获取。
     * @param callback 发送消息的回调，参考 [IRongCallback.ISendMessageCallback]。
     * 该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun sendMessage(
        message: Message,
        pushContent: String? = null,
        pushData: String? = null,
        option: SendMessageOption?,
        callback: IRongCallback.ISendMessageCallback?
    ) {
        if (messageInterceptor != null && messageInterceptor?.interceptOnSendMessage(message) == true) {
            Log.d(TAG_IM_SERVICE, "message has been intercepted.")
            return
        }
        handleBeforeSend(message)
        RongIMClient.getInstance()
            .sendMessage(
                message,
                pushContent,
                pushData,
                option,
                object : IRongCallback.ISendMessageCallback {
                    override fun onAttached(message: Message?) {
                        for (item in messageEventListeners) {
                            item.onSendMessage(SendEvent(SendEvent.ATTACH, message))
                        }
                        callback?.onAttached(message)
                    }

                    override fun onSuccess(message: Message?) {
                        filterSentMessage(message, null, null)
                        callback?.onSuccess(message)
                        if (messageInterceptor != null
                            && messageInterceptor?.interceptOnSentMessage(message) == true
                        ) {
                            Log.d(TAG_IM_SERVICE, "message has been intercepted.")
                            return
                        }
                        for (item in messageEventListeners) {
                            item.onSendMessage(SendEvent(SendEvent.SUCCESS, message))
                        }
                    }

                    override fun onError(
                        message: Message?, errorCode: RongIMClient.ErrorCode?
                    ) {
                        filterSentMessage(
                            message,
                            errorCode,
                            object : FilterSentListener {
                                override fun onComplete() {
                                    for (item in messageEventListeners) {
                                        item.onSendMessage(
                                            SendEvent(
                                                SendEvent.ERROR,
                                                message,
                                                errorCode
                                            )
                                        )
                                    }
                                }
                            })
                        callback?.onError(message, errorCode)
                    }
                })
    }

    private val sendMessageExtraStr by lazy {
        toJsonErrorNull(
            SendMessageExtra(
                versionCode = config.versionCode,
                packageName = config.packageName,
                channel = config.channel,
                platform = config.platform
            )
        )
    }

    /**
     * 发送消息之前的内部逻辑处理。
     *
     * @param message 待发送的消息
     */
    fun handleBeforeSend(message: Message) {
        //设置消息支持拓展
        message.isCanIncludeExpansion = true
        //消息拓展携带app基础信息
        val expansion = message.expansion ?: hashMapOf()
        expansion[KEY_APP_BASE_INFO] = sendMessageExtraStr
        message.setExpansion(expansion as HashMap<String, String>)
    }

    /**
     * 发送消息结果的处理
     *
     * @param message
     * @param errorCode
     */
    private fun filterSentMessage(
        message: Message?,
        errorCode: RongIMClient.ErrorCode?,
        listener: FilterSentListener?
    ) {
        if (message == null) {
            Log.e(TAG_IM_SERVICE, "filterSentMessage message is null")
            listener?.onComplete()
            return
        }
        val content = message.content
        if (content == null) {
            Log.e(TAG_IM_SERVICE, "filterSentMessage content is null")
            listener?.onComplete()
            return
        }
        if (errorCode != null && errorCode.code == CoreErrorCode.RC_VIDEO_COMPRESS_FAILED.code && message.content is SightMessage) {
            // 压缩失败不走重发队列，需要用户自己重试
            listener?.onComplete()
            return
        }
        val tag = message.content?.javaClass?.getAnnotation(MessageTag::class.java)
        if (tag != null && ((tag.flag and MessageTag.ISPERSISTED) == MessageTag.ISPERSISTED
                    || content is ReadReceiptMessage)
        ) {
            // 发送失败的消息存入重发列表
            ResendManager
                .addResendMessage(
                    message,
                    errorCode,
                    object : ResendManager.AddResendMessageCallBack {
                        override fun onComplete(
                            message: Message, errorCode: RongIMClient.ErrorCode
                        ) {
                            if (listener != null) {
                                ExecutorHelper.getInstance()
                                    .mainThread()
                                    .execute(
                                        Runnable { listener.onComplete() })
                            }
                        }
                    })
        } else {
            listener?.onComplete()
        }
    }

    fun insertIncomingMessage(
        type: Conversation.ConversationType?,
        targetId: String?,
        senderId: String?,
        receivedStatus: ReceivedStatus?,
        content: MessageContent?,
        resultCallback: RongIMClient.ResultCallback<Message>?
    ) {
        insertIncomingMessage(
            type,
            targetId,
            senderId,
            receivedStatus,
            content,
            System.currentTimeMillis(),
            resultCallback
        )
    }

    fun insertIncomingMessage(
        type: Conversation.ConversationType?,
        targetId: String?,
        senderId: String?,
        receivedStatus: ReceivedStatus?,
        content: MessageContent?,
        time: Long,
        resultCallback: RongIMClient.ResultCallback<Message>?
    ) {
        if (messageInterceptor != null
            && messageInterceptor?.interceptOnInsertIncomingMessage(
                type, targetId, senderId, receivedStatus, content, time
            ) == true
        ) {
            Log.d(TAG_IM_SERVICE, "message insertIncoming has been intercepted.")
            return
        }
        RongIMClient.getInstance()
            .insertIncomingMessage(
                type,
                targetId,
                senderId,
                receivedStatus,
                content,
                time,
                object : RongIMClient.ResultCallback<Message>() {
                    override fun onSuccess(message: Message?) {
                        if (message == null) {
                            return
                        }
                        for (item in messageEventListeners) {
                            item.onInsertMessage(InsertEvent(message))
                        }
                        resultCallback?.onSuccess(message)
                    }

                    override fun onError(errorCode: RongIMClient.ErrorCode?) {
                        resultCallback?.onError(errorCode)
                    }
                })
    }

    fun sendMediaMessage(
        message: Message,
        pushContent: String? = null,
        pushData: String? = null,
        callback: IRongCallback.ISendMediaMessageCallback?
    ) {
        sendMediaMessage(message, pushContent, pushData, SendMessageOption(), callback)
    }

    /**
     * 发送消息。 通过 [IRongCallback.ISendMessageCallback] 中的方法回调发送的消息状态及消息体。
     *
     * @param message 将要发送的消息体。
     * @param pushContent 当下发 push 消息时，在通知栏里会显示这个字段。 如果发送的是自定义消息，该字段必须填写，否则无法收到 push 消息。 如果发送 sdk
     * 中默认的消息类型，例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg，则不需要填写，默认已经指定。
     * @param pushData push 附加信息。如果设置该字段，用户在收到 push 消息时，能通过 [     ][io.rong.push.notification.PushNotificationMessage.getPushData] 方法获取。
     * @param callback 发送消息的回调，参考 [IRongCallback.ISendMediaMessageCallback]。
     * 该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     * @param option 发送消息附加选项，目前仅支持设置 isVoIPPush，如果对端设备是 iOS，设置 isVoIPPush 为 True，会走 VoIP 通道推送 Push。
     * @since 5.4.4
     */
    fun sendMediaMessage(
        message: Message,
        pushContent: String? = null,
        pushData: String? = null,
        option: SendMessageOption?,
        callback: IRongCallback.ISendMediaMessageCallback?
    ) {
        if (messageInterceptor != null && messageInterceptor?.interceptOnSendMessage(message) == true) {
            Log.d(TAG_IM_SERVICE, "message has been intercepted.")
            return
        }
        handleBeforeSend(message)
        RongIMClient.getInstance()
            .sendMediaMessage(
                message,
                pushContent,
                pushData,
                option,
                object : IRongCallback.ISendMediaMessageCallback {
                    override fun onProgress(message: Message, i: Int) {
                        for (item in messageEventListeners) {
                            item.onSendMediaMessage(
                                SendMediaEvent(
                                    SendMediaEvent.PROGRESS, message, i
                                )
                            )
                        }
                        callback?.onProgress(message, i)
                    }

                    override fun onCanceled(message: Message?) {
                        filterSentMessage(message, null, null)
                        for (item in messageEventListeners) {
                            item.onSendMediaMessage(
                                SendMediaEvent(SendMediaEvent.CANCEL, message)
                            )
                        }
                        callback?.onCanceled(message)
                    }

                    override fun onAttached(message: Message?) {
                        for (item in messageEventListeners) {
                            item.onSendMediaMessage(
                                SendMediaEvent(SendMediaEvent.ATTACH, message)
                            )
                        }
                        callback?.onAttached(message)
                    }

                    override fun onSuccess(message: Message?) {
                        filterSentMessage(message, null, null)
                        callback?.onSuccess(message)
                        if (messageInterceptor?.interceptOnSentMessage(message) == true) {
                            Log.d(TAG_IM_SERVICE, "message has been intercepted.")
                            return
                        }
                        for (item in messageEventListeners) {
                            item.onSendMediaMessage(
                                SendMediaEvent(SendMediaEvent.SUCCESS, message)
                            )
                        }
                    }

                    override fun onError(
                        message: Message?, errorCode: RongIMClient.ErrorCode?
                    ) {
                        filterSentMessage(
                            message,
                            errorCode,
                            object : FilterSentListener {
                                override fun onComplete() {
                                    for (item in messageEventListeners) {
                                        item.onSendMediaMessage(
                                            SendMediaEvent(
                                                SendMediaEvent.ERROR,
                                                message,
                                                errorCode
                                            )
                                        )
                                    }
                                }
                            })
                        callback?.onError(message, errorCode)
                    }
                })
    }

    fun sendMediaMessage(
        message: Message,
        callback: IRongCallback.ISendMediaMessageCallbackWithUploader?
    ) {
        sendMediaMessage(message, null, null, SendMessageOption(), callback)
    }

    /**
     * 发送媒体消息并且上传到自己的服务器
     */
    fun sendMediaMessage(
        message: Message,
        pushContent: String? = null,
        pushData: String? = null,
        option: SendMessageOption?,
        callback: IRongCallback.ISendMediaMessageCallbackWithUploader?
    ) {
        if (messageInterceptor != null && messageInterceptor?.interceptOnSendMessage(message) == true) {
            Log.d(TAG_IM_SERVICE, "message has been intercepted.")
            return
        }
        handleBeforeSend(message)
        val sendMediaMessageCallbackWithUploader: IRongCallback.ISendMediaMessageCallbackWithUploader =
            object : IRongCallback.ISendMediaMessageCallbackWithUploader() {
                override fun onAttached(
                    message: Message?, uploader: IRongCallback.MediaMessageUploader
                ) {
                    for (item in messageEventListeners) {
                        item.onSendMediaMessage(
                            SendMediaEvent(SendMediaEvent.ATTACH, message)
                        )
                    }
                    callback?.onAttached(message, uploader)
                }

                override fun onError(
                    message: Message?, errorCode: RongIMClient.ErrorCode?
                ) {
                    filterSentMessage(
                        message,
                        errorCode,
                        object : FilterSentListener {
                            override fun onComplete() {
                                for (item in messageEventListeners) {
                                    item.onSendMediaMessage(
                                        SendMediaEvent(
                                            SendMediaEvent.ERROR,
                                            message,
                                            errorCode
                                        )
                                    )
                                }
                            }
                        })
                    callback?.onError(message, errorCode)
                }

                override fun onProgress(message: Message?, progress: Int) {
                    for (item in messageEventListeners) {
                        item.onSendMediaMessage(
                            SendMediaEvent(SendMediaEvent.PROGRESS, message, progress)
                        )
                    }
                    callback?.onProgress(message, progress)
                }

                override fun onSuccess(message: Message?) {
                    filterSentMessage(message, null, null)
                    callback?.onSuccess(message)
                    if (messageInterceptor != null
                        && messageInterceptor?.interceptOnSentMessage(message) == true
                    ) {
                        Log.d(TAG_IM_SERVICE, "message has been intercepted.")
                        return
                    }
                    for (item in messageEventListeners) {
                        item.onSendMediaMessage(
                            SendMediaEvent(SendMediaEvent.SUCCESS, message)
                        )
                    }
                }

                override fun onCanceled(message: Message?) {
                    filterSentMessage(message, null, null)
                    for (item in messageEventListeners) {
                        item.onSendMediaMessage(
                            SendMediaEvent(SendMediaEvent.CANCEL, message)
                        )
                    }
                    callback?.onCanceled(message)
                }
            }

        RongIMClient.getInstance()
            .sendMediaMessage(
                message,
                pushContent,
                pushData,
                option,
                sendMediaMessageCallbackWithUploader
            )
    }

    /**
     * 发送已读回执，该方法会触发刷新消息未读数
     *
     *
     * 通过 [IRongCallback.ISendMessageCallback] 中的方法回调发送的消息状态及消息体。<br></br>
     * **注意：1 秒钟发送消息不能超过 5 条**。
     *
     * @param conversationType 会话类型。
     * @param targetId 会话 id。根据不同的 conversationType，可能是用户 id、讨论组 id、群组 id 或聊天室 id。
     * @param timestamp 时间戳
     * @param callback 发送消息的回调。参考 [IRongCallback.ISendMessageCallback]。
     * 该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun sendReadReceiptMessage(
        conversationType: Conversation.ConversationType?,
        targetId: String?,
        timestamp: Long,
        callback: IRongCallback.ISendMessageCallback?
    ) {
        RongIMClient.getInstance()
            .sendReadReceiptMessage(
                conversationType,
                targetId,
                timestamp,
                object : IRongCallback.ISendMessageCallback {
                    override fun onAttached(message: Message?) {
                        callback?.onAttached(message)
                    }

                    override fun onSuccess(message: Message?) {
                        filterSentMessage(message, null, null)
                        callback?.onSuccess(message)
                        for (listener in conversationEventListener) {
                            listener.onClearedUnreadStatus(
                                ConversationIdentifier.obtain(
                                    conversationType,
                                    targetId,
                                    message?.channelId
                                )
                            )
                        }
                    }

                    override fun onError(message: Message?, errorCode: RongIMClient.ErrorCode?) {
                        filterSentMessage(message, errorCode, null)
                        callback?.onError(message, errorCode)
                        for (listener in conversationEventListener) {
                            listener.onClearedUnreadStatus(
                                ConversationIdentifier.obtain(
                                    conversationType,
                                    targetId,
                                    message?.channelId
                                )
                            )
                        }
                    }
                })
    }

    /**
     * 撤回消息
     *
     * @param message 将被撤回的消息
     * @param pushContent 被撤回时，通知栏显示的信息
     * @param callback 成功回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun recallMessage(
        message: Message,
        pushContent: String?,
        callback: RongIMClient.ResultCallback<RecallNotificationMessage>?
    ) {
        RongIMClient.getInstance()
            .recallMessage(
                message,
                pushContent,
                object : RongIMClient.ResultCallback<RecallNotificationMessage>() {
                    override fun onSuccess(
                        recallNotificationMessage: RecallNotificationMessage?
                    ) {
                        if (recallNotificationMessage == null) {
                            return
                        }
                        callback?.onSuccess(recallNotificationMessage)
                        for (item in messageEventListeners) {
                            item.onRecallEvent(
                                RecallEvent(
                                    message.conversationType,
                                    message.targetId,
                                    message.messageId,
                                    recallNotificationMessage
                                )
                            )
                        }
                    }

                    override fun onError(errorCode: RongIMClient.ErrorCode?) {
                        Log.d(TAG_IM_SERVICE, "recallMessage errorCode = ${errorCode?.value}")
                        callback?.onError(errorCode)
                    }
                })
    }

    /**
     * 设置消息接收状态
     *
     * @since 5.2.5
     * @param messageId 消息 ID
     * @param conversationType 聊天类型
     * @param receivedStatus 消息接收状态
     * @param callback 回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun setMessageReceivedStatus(
        messageId: Int,
        conversationType: Conversation.ConversationType,
        targetId: String,
        receivedStatus: ReceivedStatus,
        callback: RongIMClient.ResultCallback<Boolean?>?
    ) {
        RongIMClient.getInstance()
            .setMessageReceivedStatus(
                messageId,
                receivedStatus,
                object : RongIMClient.ResultCallback<Boolean?>() {
                    override fun onSuccess(aBoolean: Boolean?) {
                        callback?.onSuccess(aBoolean)
                        changeMessageReceivedStatus(
                            messageId,
                            conversationType,
                            targetId,
                            receivedStatus
                        )
                    }

                    override fun onError(e: RongIMClient.ErrorCode?) {
                        callback?.onError(e)
                    }
                })
    }

    fun changeMessageReceivedStatus(
        messageId: Int,
        conversationType: Conversation.ConversationType,
        targetId: String,
        status: ReceivedStatus
    ) {
        for (conversationEventListener in conversationEventListener) {
            conversationEventListener.onMessageReceivedStatusChange(
                messageId, conversationType, targetId, status
            )
        }
    }

    /**
     * 获取指定会话。
     */
    fun getConversation(
        conversationType: Conversation.ConversationType?,
        targetId: String?,
        callback: RongIMClient.ResultCallback<Conversation?>?
    ) {
        RongIMClient.getInstance().getConversation(conversationType, targetId, callback)
    }

    /**
     * 清空所有会话及会话内的消息，回调方式通知是否清空成功。
     *
     * @param callback 是否清空成功的回调。
     * @param conversationTypes 会话类型。
     */
    fun clearConversations(
        callback: RongIMClient.ResultCallback<Any?>?,
        vararg conversationTypes: ConversationType
    ) {
        RongIMClient.getInstance()
            .clearConversations(
                object : RongIMClient.ResultCallback<Any?>() {
                    override fun onSuccess(o: Any?) {
                        for (listener in conversationEventListener) {
                            listener.onClearConversations(*conversationTypes)
                        }
                        callback?.onSuccess(o)
                    }

                    override fun onError(e: RongIMClient.ErrorCode) {
                        callback?.onError(e)
                    }
                },
                *conversationTypes
            )
    }

    /**
     * 清除携带指定标签的所有会话的未读消息数。
     * @param tagId 标签 ID
     * @param callback 操作结果回调
     */
    fun clearMessagesUnreadStatusByTag(tagId: String, callback: IRongCoreCallback.ResultCallback<Boolean>) {
        RongCoreClient.getInstance().clearMessagesUnreadStatusByTag(
            tagId,
            object : IRongCoreCallback.ResultCallback<Boolean>() {
                override fun onSuccess(result: Boolean) {
                    callback.onSuccess(result)
                    for (listener in conversationEventListener) {
                        listener.onClearTagConversationsUnreadStatus(tagId)
                    }
                }

                override fun onError(coreErrorCode: CoreErrorCode?) {
                    callback.onError(coreErrorCode)
                }
            }
        )
    }

    /**
     * 删除指定标签下的全部会话，同时解除这些会话和标签的绑定关系。
     * 删除成功后，会话不再携带指定的标签。这些会话收到新消息时，会产生新的会话。
     * @param tagId 标签 ID
     * @param deleteMessage 是否清除该标签下所有会话的本地历史消息
     * @param callback 操作结果回调
     */
    fun clearConversationsByTag(tagId: String, deleteMessage: Boolean, callback: IRongCoreCallback.ResultCallback<Boolean>) {
        RongCoreClient.getInstance().clearConversationsByTag(
            tagId,
            deleteMessage, // 删除消息
            object : IRongCoreCallback.ResultCallback<Boolean>() {
                override fun onSuccess(result: Boolean) {
                    callback.onSuccess(result)
                    for (listener in conversationEventListener) {
                        listener.onClearTagConversations(tagId)
                    }
                }

                override fun onError(coreErrorCode: CoreErrorCode?) {
                    callback.onError(coreErrorCode)
                }
            }
        )
    }

    /**
     * 获取当前用户已创建的标签信息。成功回调中会返回 TagInfo 列表。
     */
    fun getTags(callback: IRongCoreCallback.ResultCallback<List<TagInfo>?>?) {
        RongCoreClient.getInstance().getTags(callback)
    }

    /**
     * 创建标签，每个用户最多可以创建 20 个标签
     */
    fun addTag(tagInfo: TagInfo?, callback: IRongCoreCallback.OperationCallback?) {
        RongCoreClient.getInstance().addTag(tagInfo, callback)
    }

    /**
     * 获取指定会话历史消息。
     *
     *
     * 此方法先从本地获取历史消息，本地有缺失的情况下会从服务端同步缺失的部分；从服务端同步失败的时候会返回非 0 的 errorCode，同时把本地能取到的消息回调上去。<br></br>
     * 必须开通历史消息云存储功能。
     *
     * @param conversationType 会话类型 [io.rong.imlib.model.Conversation.ConversationType] 。
     * @param targetId 会话 id。
     * @param historyMsgOption [HistoryMessageOption]
     * @param callback 获取消息的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun getMessages(
        conversationType: Conversation.ConversationType?,
        targetId: String?,
        historyMsgOption: HistoryMessageOption?,
        callback: IRongCoreCallback.IGetMessageCallbackEx?
    ) {
        getMessages(
            ConversationIdentifier.obtain(conversationType, targetId, ""),
            historyMsgOption,
            callback
        )
    }

    /**
     * 获取指定会话历史消息。(该方法返回的消息会包含命令消息，导致无法通过消息条数判定是否还有更多消息)
     *
     *
     * 此方法先从本地获取历史消息，本地有缺失的情况下会从服务端同步缺失的部分；从服务端同步失败的时候会返回非 0 的 errorCode，同时把本地能取到的消息回调上去。<br></br>
     * 必须开通历史消息云存储功能。
     *
     * @param conversationIdentifier 会话标识
     * @param historyMsgOption [HistoryMessageOption]
     * @param callback 获取消息的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     * @param refreshMessage 是否通知会话页面刷新某条消息，默认为 true
     */
    fun getMessages(
        conversationIdentifier: ConversationIdentifier,
        historyMsgOption: HistoryMessageOption?,
        callback: IRongCoreCallback.IGetMessageCallbackEx?,
        refreshMessage: Boolean = true,
        ) {
        ChannelClient.getInstance()
            .getMessages(
                conversationIdentifier.type,
                conversationIdentifier.targetId,
                conversationIdentifier.channelId,
                historyMsgOption,
                object : IRongCoreCallback.IGetMessageCallbackEx {
                    override fun onComplete(
                        messageList: List<Message>?,
                        syncTimestamp: Long,
                        hasMoreMsg: Boolean,
                        errorCode: CoreErrorCode?
                    ) {
                        if (!messageList.isNullOrEmpty() && refreshMessage) {
                            refreshMessage(
                                messageList[messageList.size - 1]
                            )
                        }
                        callback?.onComplete(messageList, syncTimestamp, hasMoreMsg, errorCode)
                    }

                    override fun onFail(errorCode: CoreErrorCode?) {
                        callback?.onFail(errorCode)
                    }

                }
            )
    }

    /**
     * 获取指定会话历史消息。
     *
     *
     * 此方法先从本地获取历史消息，本地有缺失的情况下会从服务端同步缺失的部分；从服务端同步失败的时候会返回非 0 的 errorCode，同时把本地能取到的消息回调上去。<br></br>
     * 必须开通历史消息云存储功能。
     *
     * @param conversationIdentifier 会话标识
     * @param historyMsgOption [HistoryMessageOption]
     * @param callback 获取消息的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     * @param refreshMessage 是否通知会话页面刷新某条消息，默认为 true
     */
    fun getMessagesRecursively(
        conversationIdentifier: ConversationIdentifier,
        historyMsgOption: HistoryMessageOption?,
        callback: IRongCoreCallback.IGetMessageCallbackEx?,
        refreshMessage: Boolean = true,
    ) {
        if (historyMsgOption == null) {
            callback?.onComplete(emptyList(), 0L, false, CoreErrorCode.PARAMETER_ERROR)
            return
        }

        val expectedCount = historyMsgOption.count
        val allMessages = mutableListOf<Message>()

        fun fetchNext() {
            ChannelClient.getInstance().getMessages(
                conversationIdentifier.type,
                conversationIdentifier.targetId,
                conversationIdentifier.channelId,
                historyMsgOption,
                object : IRongCoreCallback.IGetMessageCallbackEx {
                    override fun onComplete(
                        messageList: List<Message>?,
                        syncTimestamp: Long,
                        hasMoreMsg: Boolean,
                        errorCode: CoreErrorCode?
                    ) {
                        if (errorCode != CoreErrorCode.SUCCESS) {
                            callback?.onComplete(allMessages, syncTimestamp, false, errorCode)
                            return
                        }

                        val currentList = messageList ?: emptyList()
                        allMessages.addAll(currentList)

                        val continueFetching = allMessages.size < expectedCount && hasMoreMsg
                        if (continueFetching) {
                            historyMsgOption.dataTime = allMessages.lastOrNull()?.sentTime ?: 0
                            fetchNext()
                        } else {
                            if (refreshMessage && allMessages.isNotEmpty()) {
                                refreshMessage(allMessages.last())
                            }
                            callback?.onComplete(allMessages, syncTimestamp, hasMoreMsg, errorCode)
                        }
                    }

                    override fun onFail(errorCode: CoreErrorCode?) {
                        callback?.onFail(errorCode)
                    }
                }
            )
        }

        fetchNext()
    }

    /**
     * 删除指定时间戳之前的消息，可选择是否同时删除服务器端消息
     *
     *
     * 此方法可从服务器端清除历史消息，<Strong>但是必须先开通历史消息云存储功能。</Strong> <br></br>
     * 根据会话类型和会话 id 清除某一会话指定时间戳之前的本地数据库消息（服务端历史消息）， 清除成功后只能从本地数据库（服务端）获取到该时间戳之后的历史消息。
     *
     * @param conversationType 会话类型。
     * @param targetId 会话 id。
     * @param recordTime 清除消息截止时间戳，`0 <= recordTime <= `当前会话最后一条消息的 sentTime,0
     * 清除所有消息，其他值清除小于等于 recordTime 的消息。
     * @param cleanRemote 是否删除服务器端消息
     * @param callback 清除消息的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun cleanHistoryMessages(
        conversationType: Conversation.ConversationType,
        targetId: String,
        recordTime: Long,
        cleanRemote: Boolean,
        callback: RongIMClient.OperationCallback?
    ) {
        cleanHistoryMessages(
            ConversationIdentifier.obtain(conversationType, targetId, ""),
            recordTime,
            cleanRemote,
            callback
        )
    }

    /**
     * 删除指定时间戳之前的消息，可选择是否同时删除服务器端消息
     *
     *
     * 此方法可从服务器端清除历史消息，<Strong>但是必须先开通历史消息云存储功能。</Strong> <br></br>
     * 根据会话类型和会话 id 清除某一会话指定时间戳之前的本地数据库消息（服务端历史消息）， 清除成功后只能从本地数据库（服务端）获取到该时间戳之后的历史消息。
     *
     * @param conversationIdentifier 会话标识。
     * @param recordTime 清除消息截止时间戳，`0 <= recordTime <= `当前会话最后一条消息的 sentTime,0
     * 清除所有消息，其他值清除小于等于 recordTime 的消息。
     * @param cleanRemote 是否删除服务器端消息
     * @param callback 清除消息的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun cleanHistoryMessages(
        conversationIdentifier: ConversationIdentifier,
        recordTime: Long,
        cleanRemote: Boolean,
        callback: RongIMClient.OperationCallback?
    ) {
        ChannelClient.getInstance()
            .cleanHistoryMessages(
                conversationIdentifier.type,
                conversationIdentifier.targetId,
                conversationIdentifier.channelId,
                recordTime,
                cleanRemote,
                object : IRongCoreCallback.OperationCallback() {
                    override fun onSuccess() {
                        callback?.onSuccess()
                        for (listener in conversationEventListener) {
                            listener.onClearedMessage(conversationIdentifier)
                        }
                    }

                    override fun onError(e: CoreErrorCode) {
                        callback?.onError(RongIMClient.ErrorCode.valueOf(e.code))
                        for (listener in conversationEventListener) {
                            listener.onOperationFailed(
                                RongIMClient.ErrorCode.valueOf(e.code)
                            )
                        }
                    }
                })
    }

    /**
     * 清除某会话的消息未读状态
     *
     * @param conversationType 会话类型。不支持传入 ConversationType.CHATROOM。
     * @param targetId 目标 Id。根据不同的 conversationType，可能是用户 Id、讨论组 Id、群组 Id。
     * @param callback 清除是否成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun clearMessagesUnreadStatus(
        conversationType: Conversation.ConversationType,
        targetId: String,
        callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        clearMessagesUnreadStatus(
            ConversationIdentifier.obtain(conversationType, targetId, ""), callback
        )
    }

    /**
     * 清除某会话的消息未读状态
     *
     * @param conversationIdentifier 会话标识。
     * @param callback 清除是否成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun clearMessagesUnreadStatus(
        conversationIdentifier: ConversationIdentifier,
        callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        ChannelClient.getInstance()
            .clearMessagesUnreadStatus(
                conversationIdentifier.type,
                conversationIdentifier.targetId,
                conversationIdentifier.channelId,
                object : IRongCoreCallback.ResultCallback<Boolean?>() {
                    override fun onSuccess(bool: Boolean?) {
                        callback?.onSuccess(bool)
                        for (listener in conversationEventListener) {
                            listener.onClearedUnreadStatus(conversationIdentifier)
                        }
                    }

                    override fun onError(e: CoreErrorCode) {
                        callback?.onError(RongIMClient.ErrorCode.valueOf(e.code))
                    }
                })
    }

    /**
     * 清除某一会话的文字消息草稿，回调方式获取清除是否成功。
     *
     * @param conversationType 会话类型。
     * @param targetId 目标 Id。根据不同的 conversationType，可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
     * @param callback 是否清除成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun clearTextMessageDraft(
        conversationType: Conversation.ConversationType?,
        targetId: String?,
        callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        RongIMClient.getInstance().clearTextMessageDraft(conversationType, targetId, callback)
    }

    /**
     * 保存文字消息草稿，回调方式获取保存是否成功。
     *
     * @param conversationType 会话类型。
     * @param targetId 目标 Id。根据不同的 conversationType，可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
     * @param content 草稿的文字内容。
     * @param callback 是否保存成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun saveTextMessageDraft(
        conversationType: Conversation.ConversationType?,
        targetId: String?,
        content: String?,
        callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        saveTextMessageDraft(
            ConversationIdentifier.obtain(conversationType, targetId, ""), content, callback
        )
    }

    /**
     * 保存文字消息草稿，回调方式获取保存是否成功。
     *
     * @param conversationIdentifier 会话标识。
     * @param content 草稿的文字内容。
     * @param callback 是否保存成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun saveTextMessageDraft(
        conversationIdentifier: ConversationIdentifier?,
        content: String?,
        callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        if (conversationIdentifier == null) {
            Log.e(TAG_IM_SERVICE, "saveTextMessageDraft conversationIdentifier is null")
            callback?.onError(RongIMClient.ErrorCode.PARAMETER_ERROR)
            return
        }
        ChannelClient.getInstance()
            .saveTextMessageDraft(
                conversationIdentifier.type,
                conversationIdentifier.targetId,
                conversationIdentifier.channelId,
                content,
                object : IRongCoreCallback.ResultCallback<Boolean>() {
                    override fun onSuccess(value: Boolean) {
                        callback?.onSuccess(value)
                        if (value) {
                            for (listener in conversationEventListener) {
                                listener.onSaveDraft(conversationIdentifier, content)
                            }
                        }
                    }

                    override fun onError(e: CoreErrorCode) {
                        callback?.onError(RongIMClient.ErrorCode.valueOf(e.code))
                        for (listener in conversationEventListener) {
                            listener.onOperationFailed(
                                RongIMClient.ErrorCode.valueOf(e.code)
                            )
                        }
                    }
                })
    }

    /**
     * 从会话列表中移除某一会话，但是不删除会话内的消息。
     *
     *
     * 如果此会话中有新的消息，该会话将重新在会话列表中显示，并显示最近的历史消息。
     *
     * @param type 会话类型。
     * @param targetId 目标 Id。根据不同的 conversationType，可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
     * @param callback 移除会话是否成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun removeConversation(
        type: Conversation.ConversationType?,
        targetId: String?,
        callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        RongIMClient.getInstance()
            .removeConversation(
                type,
                targetId,
                object : RongIMClient.ResultCallback<Boolean>() {
                    override fun onSuccess(bool: Boolean) {
                        callback?.onSuccess(bool)
                        if (bool) {
                            for (listener in conversationEventListener) {
                                listener.onConversationRemoved(type, targetId)
                            }
                        }
                    }

                    override fun onError(e: RongIMClient.ErrorCode) {
                        callback?.onError(e)
                    }
                })
    }

    /**
     * 查询某一会话为置顶状态
     */
    fun isConversationToTop(
        conversationIdentifier: ConversationIdentifier,
        callback: IRongCoreCallback.ResultCallback<Boolean>?
    ) {
        RongCoreClient.getInstance().getConversationTopStatus(
            conversationIdentifier.targetId,
            conversationIdentifier.type,
            callback
        )
    }

    /**
     * 设置某一会话为置顶或者取消置顶，回调方式获取设置是否成功。
     *
     * @param conversationIdentifier 会话标识。
     * @param isTop 是否置顶。
     * @param callback 设置置顶或取消置顶是否成功的回调。 该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun setConversationToTop(
        conversationIdentifier: ConversationIdentifier,
        isTop: Boolean,
        callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        ChannelClient.getInstance()
            .setConversationToTop(
                conversationIdentifier.type,
                conversationIdentifier.targetId,
                conversationIdentifier.channelId,
                isTop,
                object : IRongCoreCallback.ResultCallback<Boolean?>() {
                    override fun onSuccess(bool: Boolean?) {
                        callback?.onSuccess(bool)
                        for (listener in conversationStatusObserverList) {
                            val conversationStatus =
                                ConversationStatus()
                            conversationStatus.targetId = conversationIdentifier.targetId
                            conversationStatus.setConversationType(
                                conversationIdentifier.typeValue
                            )
                            val statusMap = java.util.HashMap<String, String>()
                            statusMap[ConversationStatus.TOP_KEY] = if (isTop
                            ) ConversationStatus.TopStatus.TOP.value
                            else ConversationStatus.TopStatus.UNTOP.value
                            conversationStatus.status = statusMap
                            listener.onStatusChanged(
                                arrayOf(conversationStatus)
                            )
                        }
                    }

                    override fun onError(e: CoreErrorCode) {
                        callback?.onError(RongIMClient.ErrorCode.valueOf(e.code))
                    }
                })
    }

    /**
     * 主动获取指定会话类型的所有置顶会话。
     */
    fun getTopConversationList(
        conversationTypes: Array<ConversationType>,
        callback: RongIMClient.ResultCallback<List<Conversation>?>
    ) {
        RongIMClient.getInstance()
            .getTopConversationList(object : RongIMClient.ResultCallback<List<Conversation>?>() {
                override fun onSuccess(conversations: List<Conversation>?) {
                    callback.onSuccess(conversations)
                }

                override fun onError(e: RongIMClient.ErrorCode?) {
                    callback.onError(e)
                }
            }, *conversationTypes)
    }

    /**
     * 向本地会话中插入一条消息，方向为发送。这条消息只是插入本地会话，不会实际发送给服务器和对方。 插入消息需为入库消息，即 [ ][MessageTag.ISPERSISTED]，否者会回调 [RongIMClient.ErrorCode.PARAMETER_ERROR]
     *
     * @param type 会话类型。
     * @param targetId 目标会话Id。比如私人会话时，是对方的id； 群组会话时，是群id; 讨论组会话时，则为该讨论,组的id.
     * @param sentStatus 接收状态 @see [Message.ReceivedStatus]
     * @param content 消息内容。如[TextMessage] [ImageMessage]等。
     * @param resultCallback 获得消息发送实体的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun insertOutgoingMessage(
        type: Conversation.ConversationType,
        targetId: String,
        sentStatus: SentStatus,
        content: MessageContent,
        resultCallback: RongIMClient.ResultCallback<Message>?
    ) {
        insertOutgoingMessage(
            ConversationIdentifier.obtain(type, targetId, ""),
            sentStatus,
            content,
            System.currentTimeMillis(),
            resultCallback
        )
    }

    fun insertOutgoingMessage(
        type: Conversation.ConversationType,
        targetId: String,
        sentStatus: SentStatus,
        content: MessageContent,
        time: Long,
        resultCallback: RongIMClient.ResultCallback<Message>?
    ) {
        insertOutgoingMessage(
            ConversationIdentifier.obtain(type, targetId, ""),
            sentStatus,
            content,
            time,
            resultCallback
        )
    }

    /**
     * 向本地会话中插入一条消息，方向为发送。这条消息只是插入本地会话，不会实际发送给服务器和对方。 插入消息需为入库消息，即 [ ][MessageTag.ISPERSISTED]，否者会回调 [RongIMClient.ErrorCode.PARAMETER_ERROR]
     *
     * @param conversationIdentifier 会话标识。
     * @param sentStatus 发送状态 @see [Message.SentStatus]
     * @param content 消息内容。如[TextMessage] [ImageMessage]等。
     * @param time 插入消息所要模拟的发送时间。
     * @param resultCallback 获得消息发送实体的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun insertOutgoingMessage(
        conversationIdentifier: ConversationIdentifier,
        sentStatus: SentStatus,
        content: MessageContent,
        time: Long,
        resultCallback: RongIMClient.ResultCallback<Message>?
    ) {
        if (messageInterceptor != null
            && messageInterceptor?.interceptOnInsertOutgoingMessage(
                conversationIdentifier.type,
                conversationIdentifier.targetId,
                sentStatus,
                content,
                time,
                resultCallback
            ) == true
        ) {
            Log.d(TAG_IM_SERVICE, "message insertOut has been intercepted.")
            return
        }
        ChannelClient.getInstance()
            .insertOutgoingMessage(
                conversationIdentifier.type,
                conversationIdentifier.targetId,
                conversationIdentifier.channelId,
                sentStatus,
                content,
                time,
                object : IRongCoreCallback.ResultCallback<Message>() {
                    override fun onSuccess(message: Message?) {
                        if (message == null) {
                            return
                        }
                        for (item in messageEventListeners) {
                            item.onInsertMessage(InsertEvent(message))
                        }
                        resultCallback?.onSuccess(message)
                    }

                    override fun onError(errorCode: CoreErrorCode) {
                        resultCallback?.onError(
                            RongIMClient.ErrorCode.valueOf(errorCode.value)
                        )
                    }
                })
    }

    /**
     * 清除指定会话的消息。
     *
     *
     * 此接口会删除指定会话中数据库的所有消息，同时，会清理数据库空间。 如果数据库特别大，超过几百 M，调用该接口会有少许耗时。
     *
     * @param conversationType 要删除的消息 Id 数组。
     * @param targetId 目标 Id。根据不同的 conversationType，可能是用户 Id、讨论组 Id、群组 Id。
     * @param callback 是否删除成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun deleteMessages(
        conversationType: Conversation.ConversationType,
        targetId: String,
        callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        RongIMClient.getInstance()
            .deleteMessages(
                conversationType,
                targetId,
                object : RongIMClient.ResultCallback<Boolean>() {
                    override fun onSuccess(bool: Boolean) {
                        if (bool) {
                            for (item in messageEventListeners) {
                                item.onClearMessages(
                                    ClearEvent(conversationType, targetId)
                                )
                            }
                        }
                        callback?.onSuccess(bool)
                    }

                    override fun onError(e: RongIMClient.ErrorCode) {
                        callback?.onError(e)
                    }
                })
    }

    /**
     * 删除会话里的一条或多条消息。
     *
     * @param conversationType 会话类型
     * @param targetId 会话 Id
     * @param messageIds 待删除的消息 Id 数组。
     * @param callback 删除操作的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun deleteMessages(
        conversationType: Conversation.ConversationType,
        targetId: String,
        messageIds: IntArray,
        callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        RongIMClient.getInstance()
            .deleteMessages(
                messageIds,
                object : RongIMClient.ResultCallback<Boolean>() {
                    override fun onSuccess(aBoolean: Boolean) {
                        if (aBoolean) {
                            for (item in messageEventListeners) {
                                item.onDeleteMessage(
                                    DeleteEvent(
                                        conversationType, targetId, messageIds
                                    )
                                )
                            }
                        }
                        callback?.onSuccess(aBoolean)
                    }

                    override fun onError(errorCode: RongIMClient.ErrorCode) {
                        callback?.onError(errorCode)
                    }
                })
    }

    /**
     * 删除指定的一条或者一组消息。会同时删除本地和远端消息。
     *
     *
     * 请注意，此方法会删除远端消息，请慎重使用
     *
     *
     * 5.6.9版本以下不支持超级群会话类型，从 5.6.9 版本开始支持超级群会话类型
     *
     * @param conversationType 会话类型。暂时不支持聊天室
     * @param targetId 目标 Id。根据不同的 conversationType，可能是用户 Id、客服 Id。
     * @param messages 要删除的消息数组, 数组大小不能超过100条。
     * @param callback 是否删除成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun deleteRemoteMessages(
        conversationType: Conversation.ConversationType,
        targetId: String,
        messages: Array<Message>,
        callback: RongIMClient.OperationCallback?
    ) {
        deleteRemoteMessages(
            ConversationIdentifier.obtain(conversationType, targetId, ""), messages, callback
        )
    }

    /**
     * 删除指定的一条或者一组消息。会同时删除本地和远端消息。
     *
     *
     * 请注意，此方法会删除远端消息，请慎重使用
     *
     *
     * 5.6.9版本以下不支持超级群会话类型，从 5.6.9 版本开始支持超级群会话类型
     *
     * @param identifier 会话标识。会话类型不支持聊天室。
     * @param messages 要删除的消息数组, 数组大小不能超过100条。
     * @param callback 是否删除成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     * @since 5.6.9
     */
    fun deleteRemoteMessages(
        identifier: ConversationIdentifier,
        messages: Array<Message>,
        callback: RongIMClient.OperationCallback?
    ) {
        ChannelClient.getInstance()
            .deleteRemoteMessages(
                identifier.type,
                identifier.targetId,
                identifier.optChannelId(),
                messages,
                object : IRongCoreCallback.OperationCallback() {
                    override fun onSuccess() {
                        val messageIds = IntArray(messages.size)
                        for (i in messages.indices) {
                            messageIds[i] = messages[i].messageId
                        }
                        for (item in messageEventListeners) {
                            item.onDeleteMessage(
                                DeleteEvent(
                                    identifier.type,
                                    identifier.targetId,
                                    messageIds
                                )
                            )
                        }
                        callback?.onSuccess()
                    }

                    override fun onError(errorCode: CoreErrorCode) {
                        callback?.onError(
                            RongIMClient.ErrorCode.valueOf(errorCode.code)
                        )
                    }
                })
    }

    /**
     * 通知会话页面刷新某条消息
     *
     * @param message
     */
    fun refreshMessage(message: Message) {
        for (item in messageEventListeners) {
            item.onRefreshEvent(RefreshEvent(message))
        }
    }

    /**
     * 根据消息 Message 设置消息状态，回调方式获取设置是否成功。
     *
     * @param message 消息实体。要设置的发送状态包含在 message 中
     * @param callback 是否设置成功的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun setMessageSentStatus(
        message: Message, callback: RongIMClient.ResultCallback<Boolean>?
    ) {
        if (message.messageId <= 0 || message.sentStatus == null) {
            Log.e(TAG_IM_SERVICE, "setMessageSentStatus message is null or messageId <= 0")
            callback?.onError(RongIMClient.ErrorCode.PARAMETER_ERROR)
            return
        }
        RongIMClient.getInstance()
            .setMessageSentStatus(
                message,
                object : RongIMClient.ResultCallback<Boolean>() {
                    override fun onSuccess(bool: Boolean) {
                        callback?.onSuccess(bool)

                        if (bool) {
                            refreshMessage(message)
                        }
                    }

                    override fun onError(e: RongIMClient.ErrorCode) {
                        callback?.onError(e)
                    }
                })
    }

    /**
     * 设置未读消息数变化监听器。 注意:如果是在 activity 中设置,那么要在 activity 销毁时, 调用 [ ][UnReadMessageManager.removeObserver] 否则会造成内存泄漏。
     *
     * @param observer 接收未读消息消息的监听器。
     * @param conversationTypes 接收未读消息的会话类型。
     */
    fun addUnReadMessageCountChangedObserver(
        observer: UnReadMessageManager.IUnReadMessageObserver,
        conversationTypes: Array<Conversation.ConversationType>
    ) {
        UnReadMessageManager.addForeverObserver(conversationTypes, observer)
    }

    /**
     * 设置未读消息数变化监听器(针对某个会话)。 注意:如果是在 activity 中设置,那么要在 activity 销毁时, 调用 [ ][UnReadMessageManager.removeObserver] 否则会造成内存泄漏。
     *
     * @param observer 接收未读消息消息的监听器。
     * @param conversationType 接收未读消息的会话类型。
     * @param targetId 接收未读消息的会话TargetId。
     */
    fun addUnReadMessageCountChangedObserver(
        observer: UnReadMessageManager.IUnReadMessageObserver,
        conversationType: Conversation.ConversationType,
        targetId: String
    ) {
        UnReadMessageManager.addForeverObserver(conversationType, targetId, observer)
    }

    /**
     * 注销已注册的未读消息数变化监听器。
     *
     * @param observer 接收未读消息消息的监听器。
     */
    fun removeUnReadMessageCountChangedObserver(
        observer: UnReadMessageManager.IUnReadMessageObserver
    ) {
        UnReadMessageManager.removeForeverObserver(observer)
    }

    /**
     * 同步未读数
     */
    fun syncUnreadCount() {
        UnReadMessageManager.syncUnreadCount()
    }

    /**
     * 取消下载多媒体文件。
     *
     * @param message 包含多媒体文件的消息，即[MessageContent]为 FileMessage, ImageMessage 等。
     * @param callback 取消下载多媒体文件时的回调。该回调在主线程中执行，请避免在回调中执行耗时操作，防止 SDK 线程阻塞。
     */
    fun cancelDownloadMediaMessage(
        message: Message, callback: RongIMClient.OperationCallback?
    ) {
        RongIMClient.getInstance().cancelDownloadMediaMessage(message, callback)
    }

    /**
     * 获取当前连接用户的信息。
     *
     * @return 当前连接用户的信息。
     */
    fun getCurrentUserId(): String {
        return RongIMClient.getInstance().currentUserId
    }

    fun getUnreadConversationList(
        callback: IRongCoreCallback.ResultCallback<List<Conversation>?>,
        vararg conversationTypes: Conversation.ConversationType
    ) {
        RongCoreClient.getInstance().getUnreadConversationList(callback, *conversationTypes)
    }

    /**
     * 分页获取会话列表
     */
    fun getConversationListByPage(
        callback: IRongCoreCallback.ResultCallback<List<Conversation>?>?,
        timeStamp: Long,
        count: Int,
        topPriority: Boolean,
        vararg conversationTypes: Conversation.ConversationType?
    ) {
        RongCoreClient.getInstance()
            .getConversationListByPage(callback, timeStamp, count, topPriority, *conversationTypes)
    }

    /**
     * 批量获取会话信息
     */
    fun getConversations(
        conversationIdentifiers: List<ConversationIdentifier>,
        callback: IRongCoreCallback.ResultCallback<List<Conversation>?>?,
    ) {
        RongCoreClient.getInstance().getConversations(conversationIdentifiers, callback)
    }

    /**
     * 更新消息拓展
     */
    fun updateMessageExpansion(
        message: Message,
        expansionMap: Map<String, String>,
        callback: RongIMClient.OperationCallback?
    ) {
        RongIMClient.getInstance().updateMessageExpansion(
            expansionMap,
            message.uId,
            object: RongIMClient.OperationCallback() {
                override fun onSuccess() {
                    for (item in messageExpansionListeners) {
                        item.onMessageExpansionUpdate(expansionMap, message)
                    }
                }

                override fun onError(errorCode: RongIMClient.ErrorCode?) {

                }
            }
        )
    }

    /**
     * 分页获取标签会话列表
     */
    fun getConversationsFromTagByPage(
        tagId: String,
        timeStamp: Long,
        count: Int,
        callback: IRongCoreCallback.ResultCallback<List<Conversation>?>?
    ) {
        RongCoreClient.getInstance()
            .getConversationsFromTagByPage(tagId, timeStamp, count, callback)
    }

    /**
     * 添加会话到标签
     */
    fun addConversationsToTag(
        tagId: String,
        conversationIdentifierList: List<ConversationIdentifier>,
        callback: IRongCoreCallback.OperationCallback?
    ) {
        RongCoreClient.getInstance()
            .addConversationsToTag(tagId, conversationIdentifierList, callback)
    }

    /**
     * 从标签移除会话
     */
    fun removeConversationsFromTag(
        tagId: String,
        conversationIdentifierList: List<ConversationIdentifier>,
        callback: IRongCoreCallback.OperationCallback?
    ) {
        RongCoreClient.getInstance()
            .removeConversationsFromTag(tagId, conversationIdentifierList, callback)
    }

    /**
     * 获取标签会话的未读数
     */
    fun getUnreadCountByTag(
        tagId: String,
        containBlocked: Boolean,
        callback: IRongCoreCallback.ResultCallback<Int>?
    ) {
        RongCoreClient.getInstance()
            .getUnreadCountByTag(tagId, containBlocked, callback)
    }



    interface FilterSentListener {
        fun onComplete()
    }
}