package com.remax.visualnovel.repository.api


import android.os.Handler
import android.os.Looper
import com.google.gson.Gson
import com.netease.nimlib.sdk.NIMClient
import com.netease.nimlib.sdk.v2.conversation.V2NIMConversationService
import com.netease.nimlib.sdk.v2.message.V2NIMMessage
import com.netease.nimlib.sdk.v2.message.V2NIMMessageListener
import com.netease.nimlib.sdk.v2.message.V2NIMMessageService
import com.netease.nimlib.sdk.v2.message.enums.V2NIMMessageQueryDirection
import com.netease.nimlib.sdk.v2.message.option.V2NIMCloudMessageListOption
import com.remax.visualnovel.api.service.MessageService
import com.remax.visualnovel.entity.imbean.IMMessageWrapper
import com.remax.visualnovel.entity.request.AIListRequest
import com.remax.visualnovel.entity.request.Gift
import com.remax.visualnovel.entity.request.PageQuery
import com.remax.visualnovel.entity.request.SendGift
import com.remax.visualnovel.entity.response.Character
import com.remax.visualnovel.entity.response.base.ApiFailedResponse
import com.remax.visualnovel.entity.response.base.Response
import com.remax.visualnovel.extension.resumeWithActive
import com.remax.visualnovel.manager.login.LoginManager
import com.remax.visualnovel.manager.nim.FetchResult
import com.remax.visualnovel.manager.nim.LoadStatus
import com.remax.visualnovel.manager.nim.NimManager
import com.remax.visualnovel.repository.api.base.BaseRepository
import com.remax.visualnovel.repository.ext.convertMessage
import com.remax.visualnovel.ui.wallet.manager.WalletManager
import kotlinx.coroutines.suspendCancellableCoroutine
import javax.inject.Inject


/**
 * Created by HJW on 2022/11/15
 */
class MessageRepository @Inject constructor(private val messageService: MessageService) : BaseRepository() {

    private val v2NIMConversationService by lazy {
        NIMClient.getService(V2NIMConversationService::class.java)
    }

    /**
     * 批量删除会话
     */
    fun deleteConversationListByIds(ids: List<String>, callback: () -> Unit) {
        v2NIMConversationService.deleteConversationListByIds(ids, true, {
            NimManager.log("删除会话成功 ${Gson().toJson(it)}")
            callback.invoke()
        }) {
            NimManager.log("删除会话失败 ${Gson().toJson(it)}")
        }
    }

    suspend fun deleteConversation(aiIdList: List<String>) = executeHttp {
        messageService.deleteConversation(AIListRequest(aiIdList))
    }

    private val messageFetchResult = FetchResult<List<IMMessageWrapper>>(LoadStatus.Finish)

    /**
     * 分页查询历史消息
     */
    suspend fun getMessageList(conversationId: String, anchorMessage: V2NIMMessage? = null, character: Character?) =
        suspendCancellableCoroutine { coroutine ->
            coroutine.invokeOnCancellation {
                coroutine.resumeWithActive(messageFetchResult)
            }
            val optionBuilder = V2NIMCloudMessageListOption.V2NIMCloudMessageListOptionBuilder
                .builder(conversationId)
                .withDirection(V2NIMMessageQueryDirection.V2NIM_QUERY_DIRECTION_DESC)

            if (anchorMessage != null) {
                optionBuilder.withAnchorMessage(anchorMessage)
                optionBuilder.withEndTime(anchorMessage.createTime)
            }

            val option = optionBuilder.build()
            // 此处避免在获取 anchor 消息后被之前消息添加导致ui移位，因此将 anchor 之前消息请求添加到后续的主线程事件队列中
            Handler(Looper.getMainLooper())
                .post {
                    // 调用接口
                    v2MessageService.getCloudMessageList(option, { result ->
                        NimManager.log("查询云端消息成功")
                        val messages = result?.messages
                        val anchorMessage = result.anchorMessage
                        NimManager.log("获取到 " + messages?.size + " 条消息")

                        val loadStatus = if (messages.isNullOrEmpty()) LoadStatus.Finish else LoadStatus.Success
                        messageFetchResult.loadStatus = loadStatus
                        messageFetchResult.data = messages?.convertMessage(anchorMessage != null, character)
                        messageFetchResult.extraInfo = anchorMessage

                        if (anchorMessage != null) {
                            NimManager.log("还有更多消息，下次查询锚点: " + anchorMessage.messageClientId)
                        } else {
                            NimManager.log("没有更多消息了")
                        }

                        coroutine.resumeWithActive(messageFetchResult)
                    }) { error ->
                        NimManager.log("查询云端消息失败, code: " + error.code + ", message: " + error.desc)
                        messageFetchResult.setError(error.code, error.desc)
                        messageFetchResult.data = null
                        messageFetchResult.extraInfo = null

                        coroutine.resumeWithActive(messageFetchResult)
                    }
                }
        }

    private val v2MessageService by lazy {
        NIMClient.getService(V2NIMMessageService::class.java)
    }

    /**
     * 添加消息监听
     */
    fun setMessageListener(register: Boolean, listener: V2NIMMessageListener) {
        if (register) {
            v2MessageService.addMessageListener(listener)
        } else {
            v2MessageService.removeMessageListener(listener)
        }
    }

    /**
     * 接收方消息已读
     */
    fun sendP2PMessageReceipt(v2Message: V2NIMMessage) {
        v2MessageService.sendP2PMessageReceipt(v2Message, {
            NimManager.log("接收方消息已读: $v2Message")
        }) {
            NimManager.log("接收方消息已读失败 ${it.code} -- ${it.desc}")
        }
    }

    fun sendMessage(v2Message: V2NIMMessage, accountId: String?, errorCallback: (Int) -> Unit) {
        NimManager.v2SendMessage(v2Message, accountId, errorCallback)
    }

    suspend fun sendGift(dto: SendGift, gift: Gift): Response<Any> {
        val totalPrice = gift.price * dto.num
        return if (totalPrice > WalletManager.balance) {
            WalletManager.showChargeDialog()
            ApiFailedResponse()
        } else {
            executeHttp {
                messageService.sendGift(dto)
            }.transformResult({
                WalletManager.refreshWallet()
            })
        }
    }

    suspend fun getMessageStat() = executeHttp(false) {
        messageService.getMessageStat()
    }.transformResult({
        LoginManager.contactUnreadCount = it?.unRead ?: 0
    })

    /**
     * 系统通知列表
     */
    suspend fun getMessageList(pn: Int) = executeHttp {
        messageService.getMessageList(PageQuery(pn))
    }

}

