package com.adealink.frame.imkit.resend

import android.os.Handler
import android.os.HandlerThread
import android.text.TextUtils
import com.adealink.frame.imkit.IMService
import com.adealink.frame.imkit.model.TAG_IM_RESEND
import com.adealink.frame.log.Log
import io.rong.imlib.IRongCallback
import io.rong.imlib.IRongCoreEnum
import io.rong.imlib.RongIMClient
import io.rong.imlib.model.Message
import io.rong.message.ImageMessage
import io.rong.message.MediaMessageContent
import io.rong.message.ReadReceiptMessage
import io.rong.message.ReferenceMessage
import java.util.Hashtable
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.concurrent.Volatile

/** 用于管理重新发送  */
object ResendManager {

    // 发送消息间隔
    private const val TIME_DELAY = 300
    @Volatile
    private var isProcessing = false
    private val messageMap: Hashtable<Int, Message> = Hashtable()
    private val messageQueue: ConcurrentLinkedQueue<Int> = ConcurrentLinkedQueue()
    private val resendHandler: Handler
    private val connectionStatusListener =
        RongIMClient.ConnectionStatusListener { connectionStatus ->
            if (connectionStatus == RongIMClient.ConnectionStatusListener.ConnectionStatus.CONNECTED) {
                // 开始发送缓存队列因发送失败需要重发的消息
                beginResend()
            } else if (connectionStatus == RongIMClient.ConnectionStatusListener.ConnectionStatus.SIGN_OUT) {
                removeAllResendMessage()
            }
        }

    init {
        val resendThread = HandlerThread("RESEND_WORK")
        resendThread.start()
        resendHandler = Handler(resendThread.looper)
        IMService.innerService.addConnectionStatusListener(connectionStatusListener)
    }

    fun addResendMessage(
        message: Message,
        errorCode: RongIMClient.ErrorCode?,
        callBack: AddResendMessageCallBack
    ) {
        resendHandler.post(
            Runnable {
                if (errorCode == null) {
                    return@Runnable
                }
                if (isResendErrorCode(errorCode)) {
                    if (!messageMap.containsKey(message.messageId)) {
                        Log.d(TAG_IM_RESEND, "addResendMessage : id=" + message.messageId)
                        messageMap[message.messageId] = message
                        messageQueue.add(message.messageId)
                        beginResend()
                        message.sentStatus = Message.SentStatus.SENDING
                    }
                }
                callBack.onComplete(message, errorCode)
            })
    }

    fun removeResendMessage(messageId: Int) {
        resendHandler.post {
            messageMap.remove(messageId)
            messageQueue.remove(messageId)
        }
    }

    fun removeResendMessages(messageIds: IntArray?) {
        if (messageIds == null || messageIds.isEmpty()) {
            return
        }
        resendHandler.post {
            for (messageId in messageIds) {
                messageMap.remove(messageId)
                messageQueue.remove(messageId)
            }
        }
    }

    fun removeAllResendMessage() {
        resendHandler.post {
            messageMap.clear()
            messageQueue.clear()
            isProcessing = false
        }
    }

    fun needResend(messageId: Int): Boolean {
        return messageMap.containsKey(messageId)
    }

    fun beginResend() {
        resendHandler.post(
            Runnable {
                if (messageMap.size == 0) {
                    Log.i(TAG_IM_RESEND, "beginResend onChanged no message need resend")
                    isProcessing = false
                    return@Runnable
                }
                if (isProcessing) {
                    Log.i(TAG_IM_RESEND, "beginResend ConnectionStatus is resending")
                    return@Runnable
                }
                isProcessing = true
                loopResendMessage()
            })
    }

    private fun loopResendMessage() {
        resendHandler.postDelayed(
            Runnable {
                val idInteger = messageQueue.peek()
                Log.d(TAG_IM_RESEND, "beginResend: messageId = $idInteger")
                if (idInteger == null
                    || IMService.innerService.getCurrentConnectionStatus()
                    != RongIMClient.ConnectionStatusListener.ConnectionStatus
                        .CONNECTED
                ) {
                    isProcessing = false
                    return@Runnable
                }
                resendMessage(
                    messageMap[idInteger],
                    object : ReSendMessageCallback {
                        override fun onCancel(message: Message?) {
                            removeResendMessage(idInteger)
                            loopResendMessage()
                        }

                        override fun onAttached(message: Message?) {
                            // do nothing
                        }

                        override fun onSuccess(message: Message?) {
                            Log.i(
                                TAG_IM_RESEND,
                                "resendMessage success messageId = "
                                        + message?.messageId
                            )
                            removeResendMessage(idInteger)
                            loopResendMessage()
                        }

                        override fun onError(
                            message: Message?, coreErrorCode: RongIMClient.ErrorCode?
                        ) {
                            Log.i(
                                TAG_IM_RESEND,
                                "resendMessage success messageId = "
                                        + message?.messageId
                            )
                            if (!isResendErrorCode(coreErrorCode)) {
                                removeResendMessage(idInteger)
                            }
                            loopResendMessage()
                        }
                    })
            },
            TIME_DELAY.toLong()
        )
    }

    /**
     * 是否为需要重发处理的错误码
     *
     * @param errorCode 发送消息的失败错误码
     * @return 是否重发，true 会重发， false 不需要重发处理。
     */
    fun isResendErrorCode(errorCode: RongIMClient.ErrorCode?): Boolean {
        val code = errorCode?.value
        return (code == IRongCoreEnum.CoreErrorCode.RC_NET_CHANNEL_INVALID.value || code == IRongCoreEnum.CoreErrorCode.RC_NET_UNAVAILABLE.value || code == IRongCoreEnum.CoreErrorCode.RC_MSG_RESP_TIMEOUT.value || code == IRongCoreEnum.CoreErrorCode.RC_FILE_UPLOAD_FAILED.value)
    }

    /**
     * 重发消息
     *
     * @param message 消息
     */
    private fun resendMessage(message: Message?, callback: ReSendMessageCallback) {
        if (message == null) {
            Log.i(TAG_IM_RESEND, "resendMessage: Message is Null")
            return
        }
        if (TextUtils.isEmpty(message.targetId) || message.content == null) {
            Log.e(TAG_IM_RESEND, "targetId or messageContent is Null")
            removeResendMessage(message.messageId)
            return
        }
        if (message.content is ImageMessage) {
            val imageMessage = message.content as ImageMessage
            if (imageMessage.remoteUri != null
                && !imageMessage.remoteUri.toString().startsWith("file")
            ) {
                IMService.innerService.sendMessage(message, null, null, callback)
            } else {
                IMService.innerService.sendMediaMessage(
                    message,
                    null,
                    null,
                    object : IRongCallback.ISendMediaMessageCallback {
                        override fun onAttached(message: Message) {
                            // do nothing
                        }

                        override fun onSuccess(message: Message) {
                            callback.onSuccess(message)
                        }

                        override fun onError(
                            message: Message, errorCode: RongIMClient.ErrorCode
                        ) {
                            callback.onError(message, errorCode)
                        }

                        override fun onProgress(message: Message, i: Int) {
                            // do nothing
                        }

                        override fun onCanceled(message: Message) {
                            // do nothing
                        }
                    })
            }
        }
        if (message.content is ReferenceMessage) {
            IMService.innerService.sendMessage(message, null, null, callback)
        } else if (message.content is ReadReceiptMessage) {
            IMService.innerService.sendReadReceiptMessage(
                message.conversationType,
                message.targetId,
                message.sentTime,
                callback
            )
        } else if (message.content is MediaMessageContent) {
            val mediaMessageContent = message.content as MediaMessageContent
            if (mediaMessageContent.mediaUrl != null) {
                IMService.innerService.sendMessage(message, null, null, callback)
            } else {
                IMService.innerService.sendMediaMessage(
                    message,
                    null,
                    null,
                    object : IRongCallback.ISendMediaMessageCallback {
                        override fun onProgress(message: Message?, progress: Int) {
                            // do nothing
                        }

                        override fun onCanceled(message: Message?) {
                            callback.onCancel(message)
                        }

                        override fun onAttached(message: Message?) {
                            // do nothing
                        }

                        override fun onSuccess(message: Message?) {
                            callback.onSuccess(message)
                        }

                        override fun onError(
                            message: Message?, errorCode: RongIMClient.ErrorCode?
                        ) {
                            callback.onError(message, errorCode)
                        }
                    })
            }
        } else {
            IMService.innerService.sendMessage(message, null, null, callback)
        }
    }

    interface AddResendMessageCallBack {
        fun onComplete(message: Message, errorCode: RongIMClient.ErrorCode)
    }

    internal interface ReSendMessageCallback : IRongCallback.ISendMessageCallback {
        /**
         * 消息被取消
         *
         * @param message 已存库的消息体。
         */
        fun onCancel(message: Message?)
    }
}
