package com.adealink.weparty.room.sdk.controller.impl

import android.os.Handler
import com.adealink.frame.base.Rlt
import com.adealink.frame.log.Log
import com.adealink.frame.room.data.FlowStateInfo
import com.adealink.frame.room.data.TAG_ROOM_MEMBER
import com.adealink.weparty.module.profile.ProfileModule
import com.adealink.weparty.module.profile.data.UserInfo
import com.adealink.weparty.room.sdk.context.IRoomContext
import com.adealink.weparty.room.sdk.controller.BaseController
import com.adealink.weparty.room.sdk.controller.IMemberController
import com.adealink.weparty.room.sdk.listener.IMemberListener
import io.trtc.tuikit.atomicxcore.api.live.LiveAudienceListener
import io.trtc.tuikit.atomicxcore.api.live.LiveAudienceStore
import io.trtc.tuikit.atomicxcore.api.live.LiveUserInfo
import kotlinx.coroutines.launch

/**
 */
class MemberController(override val ctx: IRoomContext, serialHandler: Handler) :
    BaseController<IMemberListener>(ctx, serialHandler),
    IMemberController<IMemberListener> {

    private var liveAudienceStore: LiveAudienceStore? = null

    override fun onRoomIn(flowStateInfo: FlowStateInfo) {
        super.onRoomIn(flowStateInfo)
        liveAudienceStore = LiveAudienceStore.create(flowStateInfo.roomId)
        liveAudienceStore?.addLiveAudienceListener(liveAudienceListener)
    }

    override fun onRoomLeaved(flowStateInfo: FlowStateInfo) {
        super.onRoomLeaved(flowStateInfo)
        liveAudienceStore?.removeLiveAudienceListener(liveAudienceListener)
    }

    override suspend fun getMemberInfoWithRetry(uid: String): Rlt<UserInfo> {
        var retry = 0
        var result: Rlt<UserInfo>
        do {
            result = getMemberInfo(uid)
            retry++
        } while (result is Rlt.Failed && retry < 3)
        return result
    }

    override suspend fun getMemberInfo(uid: String): Rlt<UserInfo> {
        val roomMember = ProfileModule.getCacheUserInfo(uid)
        if (roomMember != null) {
            return Rlt.Success(roomMember)
        }

        return when (val result = ProfileModule.getUserInfoByUid(uid)) {
            is Rlt.Success -> {
                Rlt.Success(result.data)
            }

            is Rlt.Failed -> {
                result
            }
        }.apply {
            Log.logRltD(TAG_ROOM_MEMBER, "getMemberInfo, uid:${uid}", this)
        }
    }

    override suspend fun getMembersInfo(uidSet: Set<String>): Rlt<Map<String, UserInfo>> {
        val uidToMemberMap = hashMapOf<String, UserInfo>()
        val noCacheMemberUidSet = hashSetOf<String>()
        uidSet.forEach {
            val roomMember = ProfileModule.getCacheUserInfo(it)
            if (roomMember == null) {
                noCacheMemberUidSet.add(it)
            } else {
                uidToMemberMap[it] = roomMember
            }
        }
        if (noCacheMemberUidSet.isEmpty()) {
            return Rlt.Success(uidToMemberMap)
        }

        return when (val result = ProfileModule.getUsersInfoByUid(noCacheMemberUidSet)) {
            is Rlt.Success -> {
                result.data.forEach {
                    uidToMemberMap[it.key] = it.value
                }
                return Rlt.Success(uidToMemberMap)

            }

            is Rlt.Failed -> result
        }.apply {
            Log.logRltD(TAG_ROOM_MEMBER, "getMembersInfo, uidSet:${uidSet}", this)
        }
    }

    private val liveAudienceListener = object : LiveAudienceListener() {
        override fun onAudienceJoined(audience: LiveUserInfo) {
            notifyAudienceJoined(audience)
        }
    }

    private fun notifyAudienceJoined(audience: LiveUserInfo) {
        launch {
            when (val userInfoRlt = ProfileModule.getUserInfoByUid(audience.userID)) {
                is Rlt.Failed -> {
                    listeners.dispatch {
                        it.onAudienceJoined(UserInfo(uid = audience.userID, nickName = audience.userName))
                    }
                }

                is Rlt.Success -> {
                    listeners.dispatch {
                        it.onAudienceJoined(userInfoRlt.data)
                    }
                }
            }
        }
    }

}