package com.adealink.frame.imkit.manager

import com.adealink.frame.imkit.listener.BaseConversationEventListener
import com.adealink.frame.imkit.listener.ConversationEventListener
import com.adealink.frame.imkit.IMService
import com.adealink.frame.imkit.event.actionevent.BaseMessageEvent
import com.adealink.frame.imkit.event.actionevent.InsertEvent
import com.adealink.frame.imkit.event.actionevent.MessageEventListener
import com.adealink.frame.imkit.model.TAG_IM_UNREAD
import com.adealink.frame.log.Log
import io.rong.imlib.IRongCoreCallback
import io.rong.imlib.IRongCoreEnum
import io.rong.imlib.RongIMClient
import io.rong.imlib.model.Conversation.ConversationType
import io.rong.imlib.model.Message

object UnReadMessageManager : RongIMClient.OnReceiveMessageWrapperListener(),
    RongIMClient.SyncConversationReadStatusListener {
    private val foreverMultiConversationUnreadInfos: MutableList<MultiConversationUnreadMsgInfo> =
        ArrayList()

    private val conversationEventListener: ConversationEventListener =
        object : BaseConversationEventListener() {
            override fun onClearedUnreadStatus(
                type: ConversationType, targetId: String
            ) {
                syncUnreadCount(type, targetId)
            }

            override fun onConversationRemoved(
                type: ConversationType, targetId: String
            ) {
                syncUnreadCount(type, targetId)
            }

            override fun onClearTagConversations(tagId: String?) {
                syncUnreadCount()
            }

            override fun onClearTagConversationsUnreadStatus(tagId: String?) {
                syncUnreadCount()
            }
        }

    private val messageEventListener: MessageEventListener = object : BaseMessageEvent() {
        override fun onInsertMessage(event: InsertEvent) {
            val message = event.message
            if ((message.messageDirection == Message.MessageDirection.RECEIVE) && !message.receivedStatus.isRead) {
                syncUnreadCount(targetId = message.targetId, conversationType = message.conversationType)
            }
        }
    }

    private val connectCallback: IRongCoreCallback.ConnectCallback =
        object : IRongCoreCallback.ConnectCallback() {
            override fun onSuccess(s: String) {
                // do nothing
            }

            override fun onError(e: IRongCoreEnum.ConnectionErrorCode?) {
                // do nothing
            }

            override fun onDatabaseOpened(code: IRongCoreEnum.DatabaseOpenStatus?) {
                syncUnreadCount()
            }
        }

    private val recallMessageListener =
        RongIMClient.OnRecallMessageListener { message, recallNotificationMessage ->
            syncUnreadCount(message.conversationType, message.targetId)
            false
        }

    init {
        IMService.innerService.addAsyncOnReceiveMessageListener(this)
        IMService.innerService.addConversationEventListener(conversationEventListener)
        IMService.innerService.addMessageEventListener(messageEventListener)
        IMService.innerService.addConnectStatusListener(connectCallback)
        IMService.innerService.addOnRecallMessageListener(recallMessageListener)
        IMService.innerService.addSyncConversationReadStatusListener(this)
    }

    override fun onSyncConversationReadStatus(
        type: ConversationType,
        targetId: String
    ) {
        syncUnreadCount(type, targetId)
    }

    override fun onReceived(
        message: Message,
        left: Int,
        hasPackage: Boolean,
        offline: Boolean
    ): Boolean {
        if (left == 0 || !hasPackage) {
            syncUnreadCount()
        }
        return false
    }

    /**
     * 同步未读数，指定会话类型和会话ID
     */
    private fun syncUnreadCount(conversationType: ConversationType, targetId: String) {
        syncForeverObserverUnreadCount(conversationType, targetId)
    }

    /**
     * 同步未读数，不指定会话类型和会话ID
     */
    fun syncUnreadCount() {
        syncForeverObserverUnreadCount()
    }

    private fun syncForeverObserverUnreadCount(conversationType: ConversationType, targetId: String) {
        if (!IMService.innerService.offlineMessageSyncCompleted()) {
            Log.e(TAG_IM_UNREAD, "syncForeverObserverUnreadCount, offlineMessageSyncCompleted:false")
            return
        }
        for (msgInfo in foreverMultiConversationUnreadInfos) {
            if (msgInfo.targetId == targetId && msgInfo.conversationTypes.contains(conversationType)) {
                //指定会话ID
                RongIMClient.getInstance()
                    .getUnreadCount(
                        msgInfo.conversationTypes[0],
                        msgInfo.targetId,
                        object : RongIMClient.ResultCallback<Int>() {
                            override fun onSuccess(integer: Int) {
                                Log.d(TAG_IM_UNREAD, "syncForeverObserverUnreadCount, conversationType:${conversationType}, targetId:${msgInfo.targetId}, getUnreadCount: $integer")
                                msgInfo.count = integer
                                msgInfo.observer?.onCountChanged(integer)
                            }

                            override fun onError(e: RongIMClient.ErrorCode) {
                                // do nothing
                            }
                        }
                    )
            }

            if (msgInfo.targetId == null && msgInfo.conversationTypes.contains(conversationType)) {
                //未指定会话ID
                RongIMClient.getInstance()
                    .getUnreadCount(
                        msgInfo.conversationTypes,
                        object : RongIMClient.ResultCallback<Int>() {
                            override fun onSuccess(integer: Int) {
                                Log.d(TAG_IM_UNREAD, "syncForeverObserverUnreadCount, conversationType:${conversationType}, getUnreadCount: $integer")
                                msgInfo.count = integer
                                msgInfo.observer?.onCountChanged(integer)
                            }

                            override fun onError(e: RongIMClient.ErrorCode) {
                                // do nothing
                            }
                        })
            }
        }
    }

    private fun syncForeverObserverUnreadCount() {
        if (!IMService.innerService.offlineMessageSyncCompleted()) {
            Log.e(TAG_IM_UNREAD, "syncForeverObserverUnreadCount, offlineMessageSyncCompleted:false")
            return
        }
        for (msgInfo in foreverMultiConversationUnreadInfos) {
            if (msgInfo.targetId != null) {
                //有指定会话类型和会话ID的观察者
                RongIMClient.getInstance()
                    .getUnreadCount(
                        msgInfo.conversationTypes[0],
                        msgInfo.targetId,
                        object : RongIMClient.ResultCallback<Int>() {
                            override fun onSuccess(integer: Int) {
                                Log.d(TAG_IM_UNREAD, "syncForeverObserverUnreadCount, conversationTypes:${msgInfo.conversationTypes.map { it.value }}, targetId:${msgInfo.targetId}, getUnreadCount: $integer")
                                msgInfo.count = integer
                                msgInfo.observer?.onCountChanged(integer)
                            }

                            override fun onError(e: RongIMClient.ErrorCode) {
                                // do nothing
                            }
                        }
                    )
            } else {
                RongIMClient.getInstance()
                    .getUnreadCount(
                        msgInfo.conversationTypes,
                        object : RongIMClient.ResultCallback<Int>() {
                            override fun onSuccess(integer: Int) {
                                Log.d(TAG_IM_UNREAD, "syncForeverObserverUnreadCount, conversationTypes:${msgInfo.conversationTypes.map { it.value }}, getUnreadCount: $integer")
                                msgInfo.count = integer
                                msgInfo.observer?.onCountChanged(integer)
                            }

                            override fun onError(e: RongIMClient.ErrorCode) {
                                // do nothing
                            }
                        })
            }
        }
    }


    /**
     * 设置未读消息数变化监听器。 注意:如果是在 activity 中设置,那么要在 activity 销毁时, 调用 [ ][UnReadMessageManager.removeObserver] 否则会造成内存泄漏。
     *
     * @param observer 接收未读消息消息的监听器。
     * @param conversationTypes 接收未读消息的会话类型。
     */
    fun addForeverObserver(
        conversationTypes: Array<ConversationType>,
        observer: IUnReadMessageObserver?,
    ) {
        if (observer == null) {
            Log.e(TAG_IM_UNREAD, "can't add a null observer!")
            return
        }
        synchronized(foreverMultiConversationUnreadInfos) {
            val msgInfo = MultiConversationUnreadMsgInfo()
            msgInfo.conversationTypes = conversationTypes
            msgInfo.observer = observer
            foreverMultiConversationUnreadInfos.add(msgInfo)
            if (!IMService.innerService.offlineMessageSyncCompleted()) {
                Log.e(TAG_IM_UNREAD, "addForeverObserver, offlineMessageSyncCompleted:false")
                return
            }
            RongIMClient.getInstance()
                .getUnreadCount(
                    conversationTypes,
                    object : RongIMClient.ResultCallback<Int>() {
                        override fun onSuccess(integer: Int) {
                            Log.d(TAG_IM_UNREAD, "addForeverObserver, conversationTypes:${conversationTypes}, getUnreadCount: $integer")
                            msgInfo.count = integer
                            msgInfo.observer?.onCountChanged(integer)
                        }

                        override fun onError(e: RongIMClient.ErrorCode) {
                            // do nothing
                        }
                    })
        }
    }

    /**
     * 设置未读消息数变化监听器（针对某个会话）。 注意:如果是在 activity 中设置,那么要在 activity 销毁时, 调用 [ ][UnReadMessageManager.removeObserver] 否则会造成内存泄漏。
     *
     * @param observer 接收未读消息消息的监听器。
     * @param conversationType 接收未读消息的会话类型。
     * @param targetId 接收未读消息的TargetID。
     */
    fun addForeverObserver(
        conversationType: ConversationType,
        targetId: String,
        observer: IUnReadMessageObserver?,
    ) {
        if (observer == null) {
            Log.e(TAG_IM_UNREAD, "can't add a null observer!")
            return
        }

        synchronized(foreverMultiConversationUnreadInfos) {
            val msgInfo = MultiConversationUnreadMsgInfo()
            msgInfo.conversationTypes = arrayOf(conversationType)
            msgInfo.targetId = targetId
            msgInfo.observer = observer
            foreverMultiConversationUnreadInfos.add(msgInfo)
            if (!IMService.innerService.offlineMessageSyncCompleted()) {
                Log.e(TAG_IM_UNREAD, "addForeverObserver, offlineMessageSyncCompleted:false")
                return
            }
            RongIMClient.getInstance()
                .getUnreadCount(
                    conversationType,
                    targetId,
                    object : RongIMClient.ResultCallback<Int>() {
                        override fun onSuccess(integer: Int) {
                            Log.d(TAG_IM_UNREAD, "addForeverObserver, conversationType:${conversationType}, targetId:${msgInfo.targetId}, getUnreadCount: $integer")
                            msgInfo.count = integer
                            msgInfo.observer?.onCountChanged(integer)
                        }

                        override fun onError(e: RongIMClient.ErrorCode) {
                            // do nothing
                        }
                    })
        }
    }

    fun removeForeverObserver(observer: IUnReadMessageObserver?) {
        if (observer == null) {
            Log.d(TAG_IM_UNREAD, "removeOnReceiveUnreadCountChangedListener Illegal argument")
            return
        }
        synchronized(foreverMultiConversationUnreadInfos) {
            var result: MultiConversationUnreadMsgInfo? = null
            for (msgInfo in foreverMultiConversationUnreadInfos) {
                if (msgInfo.observer === observer) {
                    result = msgInfo
                    break
                }
            }
            if (result != null) {
                foreverMultiConversationUnreadInfos.remove(result)
            }
        }
    }

    fun clearForeverObserver() {
        synchronized(foreverMultiConversationUnreadInfos) {
            foreverMultiConversationUnreadInfos.clear()
        }
    }

    interface IUnReadMessageObserver {
        fun onCountChanged(count: Int)
    }

    private class MultiConversationUnreadMsgInfo {
        var conversationTypes: Array<ConversationType> = arrayOf()
        var targetId: String? = null
        var count: Int = 0
        var observer: IUnReadMessageObserver? = null
    }

}
