package com.adealink.weparty.im.manager.session

import android.app.Application
import com.adealink.frame.base.CommonParamError
import com.adealink.frame.base.IError
import com.adealink.frame.base.Rlt
import com.adealink.frame.base.fastLazy
import com.adealink.frame.frame.BaseFrame
import com.adealink.frame.log.Log
import com.adealink.frame.storage.cache.TimeoutLruCache
import com.adealink.weparty.App
import com.adealink.weparty.im.data.IMIsBlackReq
import com.adealink.weparty.im.datasource.remote.IMHttpService
import com.adealink.weparty.module.im.data.TAG_IM_SESSION
import com.adealink.weparty.module.profile.ProfileModule
import com.tencent.imsdk.v2.V2TIMCallback
import com.tencent.imsdk.v2.V2TIMManager
import com.tencent.imsdk.v2.V2TIMMessage
import com.tencent.imsdk.v2.V2TIMReceiveMessageOptInfo
import com.tencent.imsdk.v2.V2TIMSDKListener
import com.tencent.imsdk.v2.V2TIMUserStatus
import com.tencent.imsdk.v2.V2TIMValueCallback
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

val sessionManager: ISessionManager by lazy { SessionManager() }

class SessionManager : BaseFrame<ISessionListener>(),
    ISessionManager {


    //会话免打扰(静音)
    private val sessionMuteCache by lazy {
        TimeoutLruCache<String, Boolean>(
            1000,
            10 * 60 * 1000
        ) //最多缓存1000个，缓存时长10分钟
    }

    //拉黑名单
    private val sessionBlackCache by lazy {
        TimeoutLruCache<String, Boolean>(
            1000,
            10 * 60 * 1000
        ) //最多缓存1000个，缓存时长10分钟
    }


    private val imHttpService by fastLazy {
        App.instance.networkService.getHttpService(IMHttpService::class.java)
    }

    override fun init(application: Application) {
        registerUserStatusChanged()
    }

    override suspend fun isSessionBlack(
        uid: String
    ): Rlt<Boolean> {
        val rlt = imHttpService.isBlack(IMIsBlackReq(uid))
        return when (rlt) {
            is Rlt.Failed -> {
                rlt
            }

            is Rlt.Success -> {
                Rlt.Success(rlt.data.data?.black ?: false)
            }
        }
    }

    override suspend fun setSessionBlack(
        uids: String,
        black: Boolean
    ): Rlt<Map<String, Boolean>> {
        return suspendCancellableCoroutine { continuation ->

        }
    }

    override suspend fun isSessionMute(
        uids: List<String>,
        chatInfoType: Int
    ): Rlt<Map<String, Boolean>> {
        return suspendCancellableCoroutine { continuation ->
            when (chatInfoType) {
                ChatInfo.TYPE_C2C -> {
                    V2TIMManager.getMessageManager().getC2CReceiveMessageOpt(uids, object :
                        V2TIMValueCallback<List<V2TIMReceiveMessageOptInfo>> {
                        override fun onSuccess(options: List<V2TIMReceiveMessageOptInfo>?) {
                            if (continuation.isActive) {
                                val muteMap = mutableMapOf<String, Boolean>()
                                options?.forEach { option ->
                                    muteMap[option.userID] =
                                        option.c2CReceiveMessageOpt == V2TIMMessage.V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE
                                    sessionMuteCache.put(
                                        option.userID,
                                        option.c2CReceiveMessageOpt == V2TIMMessage.V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE
                                    )
                                }
                                continuation.resume(Rlt.Success(muteMap))
                            }
                        }

                        override fun onError(code: Int, desc: String?) {
                            if (continuation.isActive) {
                                continuation.resume(
                                    Rlt.Failed(
                                        IError(
                                            serverCode = code,
                                            msg = desc ?: ""
                                        )
                                    )
                                )
                            }
                        }
                    })
                }

                ChatInfo.TYPE_GROUP -> {
                    //Not support
                    continuation.resume(Rlt.Failed(CommonParamError("Unsupported: group chat")))
                }
            }
        }
    }

    override suspend fun setSessionMute(
        uids: List<String>,
        chatInfoType: Int,
        mute: Boolean
    ): Rlt<Any> {
        return suspendCancellableCoroutine { continuation ->
            when (chatInfoType) {
                ChatInfo.TYPE_C2C -> {
                    V2TIMManager.getMessageManager().setC2CReceiveMessageOpt(
                        uids,
                        if (mute) {
                            V2TIMMessage.V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE
                        } else {
                            V2TIMMessage.V2TIM_RECEIVE_MESSAGE
                        },
                        object : V2TIMCallback {
                            override fun onSuccess() {
                                if (continuation.isActive) {
                                    uids.forEach { uid ->
                                        sessionMuteCache.put(uid, mute)
                                    }
                                    continuation.resume(Rlt.Success(Any()))
                                }
                            }

                            override fun onError(code: Int, desc: String?) {
                                if (continuation.isActive) {
                                    continuation.resume(
                                        Rlt.Failed(
                                            IError(
                                                serverCode = code,
                                                msg = desc ?: ""
                                            )
                                        )
                                    )
                                }
                            }
                        }
                    )
                }

                ChatInfo.TYPE_GROUP -> {
                    continuation.resume(Rlt.Failed(CommonParamError("Unsupported: group chat")))
                }
            }
        }
    }


    private val userOnlineRegisterList = mutableListOf<String>()
    override fun registerUserOnlineStatus(uid: String) {
        userOnlineRegisterList.add(uid)
        V2TIMManager.getInstance()
            .subscribeUserStatus(userOnlineRegisterList, object : V2TIMCallback {
                override fun onSuccess() {
                    Log.d(TAG_IM_SESSION, "registerUserOnlineStatus success")
                }

                override fun onError(code: Int, desc: String?) {
                    Log.e(TAG_IM_SESSION, "registerUserOnlineStatus fail, code$code, desc:$desc")
                }
            })
    }

    override fun unregisterUserOnlineStatus(uid: String) {
        userOnlineRegisterList.remove(uid)
        V2TIMManager.getInstance()
            .unsubscribeUserStatus(listOf(uid), object : V2TIMCallback {
                override fun onSuccess() {
                    Log.d(TAG_IM_SESSION, "unregisterUserOnlineStatus success")
                }

                override fun onError(code: Int, desc: String?) {
                    Log.e(TAG_IM_SESSION, "unregisterUserOnlineStatus fail, code$code, desc:$desc")
                }
            })
    }

    private fun registerUserStatusChanged() {
        Log.d(TAG_IM_SESSION, "registerUserStatusChanged")
        val v2TIMSDKListener: V2TIMSDKListener = object : V2TIMSDKListener() {
            override fun onUserStatusChanged(userStatusList: MutableList<V2TIMUserStatus?>?) {
                Log.d(
                    TAG_IM_SESSION,
                    "onUserStatusChanged, ${userStatusList?.joinToString(separator = ",") { "${it?.userID}_${it?.statusType}" }}"
                )
                userStatusList?.forEach { status ->
                    status ?: return@forEach
                    status.userID ?: return@forEach
                    ProfileModule.updateUserOnline(
                        status.userID,
                        status.statusType == V2TIMUserStatus.V2TIM_USER_STATUS_ONLINE
                    )
                }
            }
        }
        V2TIMManager.getInstance().addIMSDKListener(v2TIMSDKListener)
    }


}