package com.adealink.weparty.profile.manager

import com.adealink.frame.base.CommonDataNullError
import com.adealink.frame.base.CommonParamError
import com.adealink.frame.base.Rlt
import com.adealink.frame.data.json.froJsonErrorNull
import com.adealink.frame.data.json.toJsonErrorNull
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.module.account.AccountModule
import com.adealink.weparty.module.profile.data.UserConfigType
import com.adealink.weparty.module.profile.data.UserConfigType.Companion.NECESSARY_USER_ATTR_SET
import com.adealink.weparty.module.profile.data.UserInfo
import com.adealink.weparty.module.profile.listener.IProfileListener
import com.adealink.weparty.profile.data.GetUserinfoReq
import com.adealink.weparty.profile.datasource.remote.ProfileHttpService
import com.adealink.weparty.storage.AppPref

val profileManager: IProfileManager by lazy { ProfileManager() }

class ProfileManager : BaseFrame<IProfileListener>(), IProfileManager {

    private val profileHttpService by lazy {
        App.instance.networkService.getHttpService(ProfileHttpService::class.java)
    }

    private val userInfoCache by lazy {
        TimeoutLruCache<String, UserInfo>(
            1000,
            10 * 60 * 1000
        ) //最多缓存1000个，缓存时长10分钟
    }

    override fun getMyUid(): String {
        return AccountModule.uid
    }

    override fun getMyUserInfo(): UserInfo? {
        return userInfoCache[AccountModule.uid] ?: getMyUserInfoFromCache()
    }

    override suspend fun pullMyUserInfo(): Rlt<UserInfo?> {
        val rlt = profileHttpService.getMyUserInfo()
        return when (rlt) {
            is Rlt.Failed -> {
                rlt
            }

            is Rlt.Success -> {
                Rlt.Success(rlt.data.data?.userInfo)
            }
        }
    }

    private fun getMyUserInfoFromCache(): UserInfo? {
        val userInfoJsonString = AppPref.userInfo
        if (userInfoJsonString.isNotEmpty()) {
            return froJsonErrorNull<UserInfo>(userInfoJsonString)
        }
        return null
    }

    override fun setMyUserInfo(userInfo: UserInfo, attrSet: Set<UserConfigType>?) {
        updateUserInfoCache(userInfo.uid, userInfo, attrSet)
        getMyUserInfo()?.let { myUserInfo ->
            toJsonErrorNull(myUserInfo)?.let {
                AppPref.userInfo = it
            }
        }
    }

    override fun updateMyUserCountryInfo(country: String, region: String, countryFlag: String) {
        val myUserInfo = getMyUserInfo() ?: return
//        myUserInfo.country = country
//        myUserInfo.region = region
//        myUserInfo.flag = countryFlag
        setMyUserInfo(myUserInfo, null)
    }

    override fun getCacheUserInfo(uid: String): UserInfo? {
        return userInfoCache[uid]
    }

    override fun updateCacheUserInfo(userInfo: UserInfo) {
        updateUserInfoCache(userInfo.uid, userInfo)//5
    }

    override suspend fun getUserInfoByUid(
        uid: String,
        cache: Boolean,
        attrSet: Set<UserConfigType>?
    ): Rlt<UserInfo> {
        if (uid.isEmpty()) {
            return Rlt.Failed(CommonParamError("uid($uid) is invalid"))
        }

        if (cache) {
            val userInfo = if (uid == getMyUid()) {
                getMyUserInfo()
            } else {
                userInfoCache[uid]
            }
            if (userInfo != null && userInfo.isCacheValid(attrSet)) {
                return Rlt.Success(userInfo)
            }
        }

        val reqAttrSet = mutableSetOf<UserConfigType>().apply {
            addAll(NECESSARY_USER_ATTR_SET)
            attrSet?.let {
                addAll(it)
            }
        }
        Log.d(
            "TAG_PROFILE",
            "ProfileManager.getUserInfoByUid, uid:${uid}, reqAttrSet:${reqAttrSet.map { it.type }}"
        )
        return when (val result =
            profileHttpService.getUserInfosByUid(GetUserinfoReq(listOf(uid)))) {
            is Rlt.Success -> {
                val res = result.data.data ?: return Rlt.Failed(CommonDataNullError())
                val userInfo = res.list.firstOrNull()
                if (userInfo == null) {
                    return Rlt.Failed(CommonDataNullError())
                }
                if (uid == getMyUid()) {
                    setMyUserInfo(userInfo, reqAttrSet)
                } else {
                    updateUserInfoCache(uid, userInfo, reqAttrSet)
                }
                Rlt.Success(userInfo)
            }

            is Rlt.Failed -> {
                result
            }
        }
    }

    override suspend fun getUsersInfoByUid(
        uidSet: Set<String>,
        cache: Boolean,
        attrSet: Set<UserConfigType>?,
    ): Rlt<Map<String, UserInfo>> {
        val userInfoMap = hashMapOf<String, UserInfo>()
        val reqUidList = uidSet.toMutableList()
        if (cache) {
            uidSet.forEach { uid ->
                if (uid != getMyUid()) {
                    userInfoCache[uid]?.let {
                        if (it.isCacheValid(attrSet)) {
                            userInfoMap[uid] = it
                            reqUidList.remove(uid)
                        }
                    }
                } else {
                    getMyUserInfo()?.let {
                        if (it.isCacheValid(attrSet)) {
                            userInfoMap[uid] = it
                            reqUidList.remove(uid)
                        }
                    }
                }
            }
        }
        if (reqUidList.isEmpty()) {
            return Rlt.Success(userInfoMap)
        }

        val reqAttrSet = mutableSetOf<UserConfigType>().apply {
            addAll(NECESSARY_USER_ATTR_SET)
            attrSet?.let {
                addAll(it)
            }
        }
        val rlt = profileHttpService.getUserInfosByUid(GetUserinfoReq(reqUidList))
        if (rlt is Rlt.Success) {
            val getUserInfoResList = rlt.data.data?.list
            getUserInfoResList?.forEach {userInfo->
                userInfoMap[userInfo.uid] = userInfo
                if (userInfo.uid == AccountModule.uid) {
                    setMyUserInfo(userInfo, reqAttrSet)
                } else {
                    updateUserInfoCache(userInfo.uid, userInfo, reqAttrSet)
                }
            }
        }
        return Rlt.Success(userInfoMap)
    }

    private fun updateUserInfoCache(
        uid: String,
        userInfo: UserInfo,
        attrSet: Set<UserConfigType>? = null
    ) {
        val cacheUserInfo = userInfoCache[uid]
        if (cacheUserInfo == null) {
//            userInfo.attrSet.addAll(attrSet ?: emptySet())
            userInfoCache.put(uid, userInfo)
            return
        }
//        cacheUserInfo.updateWithUserAttr(userInfo, attrSet)
    }

    override fun clear() {
        AppPref.userInfo = ""
    }

}
