package com.adealink.weparty.account.login.manager

import android.content.Intent
import com.adealink.frame.base.CommonDataNullError
import com.adealink.frame.base.IError
import com.adealink.frame.base.Rlt
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.frame.BaseFrame
import com.adealink.frame.log.Log
import com.adealink.frame.network.ISocketNotify
import com.adealink.frame.network.data.Res
import com.adealink.frame.router.Router
import com.adealink.frame.util.AppUtil
import com.adealink.weparty.App
import com.adealink.weparty.account.constant.TAG_ACCOUNT_LOGIN
import com.adealink.weparty.account.login.LoginActivity
import com.adealink.weparty.account.login.data.AccountInfo
import com.adealink.weparty.account.login.data.GoogleLoginReq
import com.adealink.weparty.account.login.data.LoginResult
import com.adealink.weparty.account.login.data.RefreshTokenNotify
import com.adealink.weparty.account.login.data.TestLoginReq
import com.adealink.weparty.account.login.data.ThirdType
import com.adealink.weparty.account.login.data.UserKickOutNotify
import com.adealink.weparty.account.login.datasource.remote.LoginService
import com.adealink.weparty.debug.DebugActivity
import com.adealink.weparty.module.account.Account
import com.adealink.weparty.module.account.AccountLocalService
import com.adealink.weparty.module.account.AccountModule
import com.adealink.weparty.module.account.ILoginListener
import com.adealink.weparty.module.account.data.AccountErrorRefreshTokenEmpty
import com.adealink.weparty.module.account.data.AccountErrorTokenRefreshing
import com.adealink.weparty.module.account.data.SmsCountryInfo
import com.adealink.weparty.module.account.data.UserKickReason
import com.adealink.weparty.module.profile.ProfileModule
import com.adealink.weparty.storage.AppPref
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.atomic.AtomicBoolean

val loginManager: ILoginManager by lazy { LoginManager() }

class LoginManager : BaseFrame<ILoginListener>(), ILoginManager {

    private val userLoginKickNotify = object : ISocketNotify<UserKickOutNotify> {

        override val uri: String = "USER_LOGIN_KICK_NOTIFY"

        override fun needHandle(data: UserKickOutNotify?): Boolean {
            return data != null && data.kickReason == UserKickReason.REASON_KICK_ONLINE_BY_MULTIPOINT_LOGIN.value
        }

        override fun onNotify(data: UserKickOutNotify) {
            handleKickOut(data)
        }
    }

    private val refreshTokenNotify = object : ISocketNotify<RefreshTokenNotify> {

        override val uri: String = "REFRESH_TOKEN_NOTIFY"

        override fun needHandle(data: RefreshTokenNotify?): Boolean {
            return data != null
        }

        override fun onNotify(data: RefreshTokenNotify) {
            refreshToken()
        }
    }

    private val loginService by lazy { App.instance.networkService.getHttpService(LoginService::class.java) }
    private var isHandlingKickOut = false
    private val handlingRefreshToken = AtomicBoolean(false)
    private var allSmsCountryList = mutableListOf<SmsCountryInfo>()

    private var isNewRegister = false

    private var inviteUidCode: String? = null //邀请UID码
    private var inviteRoomIdCode: String? = null //邀请房间码
    private var shareScene: String? = null //分享场景

    override var uid: String = ""
        set(value) {
            field = value
            AppPref.uid = value
        }
    override var token: String = ""
        set(value) {
            field = value
            AppPref.token = value
        }
    override var isLogin: Boolean = false
        set(value) {
            field = value
            AppPref.isLogin = value
        }

    init {
        isLogin = AppPref.isLogin
        uid = AppPref.uid
        token = AppPref.token
        App.instance.networkService.subscribeNotify(userLoginKickNotify)
        App.instance.networkService.subscribeNotify(refreshTokenNotify)
    }

    private fun handleKickOut(notify: UserKickOutNotify) {
        launch(Dispatcher.UI) {
            if (notify.kickUid == AccountModule.uid) {
                if (isHandlingKickOut) {
                    return@launch
                }
                val kickOutLoginType = AccountLocalService.loginType
                isHandlingKickOut = true
                logout(false)
                if (isCurrentLoginActivity()) {
                    isHandlingKickOut = false
                    return@launch
                }
                isHandlingKickOut = false

                if (isRunLogin()) return@launch
                Router.build(AppUtil.appContext, Account.Login.PATH)
                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
                    .putExtra(Account.Common.EXTRA_KICK_OUT_REASON, notify.kickReason)
                    .putExtra(Account.Common.EXTRA_KICK_OUT_LOGIN_TYPE, kickOutLoginType)
                    .start()
            }
        }
    }


    private fun isCurrentLoginActivity(): Boolean {
        return AppUtil.currentActivity is LoginActivity
    }

    private fun handleKickOut(reason: UserKickReason, tipContent: String? = null) {
        if (isHandlingKickOut) {
            return
        }
        isHandlingKickOut = true
        logout(false)
        if (isCurrentLoginActivity()) {
            isHandlingKickOut = false
            return
        }
        isHandlingKickOut = false
        if (isRunLogin()) return
        Router.build(AppUtil.appContext, Account.Login.PATH)
            .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
            .putExtra(Account.Common.EXTRA_KICK_OUT_REASON, reason.value)
            .putExtra(Account.Common.EXTRA_KICK_OUT_CONTENT, tipContent)
            .start()
    }


    private fun isRunLogin() = AppUtil.currentActivity is DebugActivity

    override suspend fun login(
        authType: ThirdType,
        token: String,
        tid: Long?,
        codeVerifier: String?
    ): Rlt<Res<LoginResult>> {

        when (authType) {
            ThirdType.GOOGLE -> {
                return googleLogin(token)
            }

            ThirdType.PHONE -> {}
            ThirdType.EMAIL -> {}
        }

//        val newDeviceId = App.instance.deviceIdService.getNewDeviceIdErrorEmpty()
//        val isEmulator = App.instance.securityService.isEmulator()
//        val isVirtualApk = App.instance.securityService.isVirtualApk()
//        val appsflyerId = AttributionModule.getAppsFlyerUID()
//        val deviceToken = TCTuringManager.getDeviceToken()
//        var tidReq: Long? = null //用户登录tid
//        Log.i(TAG_ACCOUNT_LOGIN, "login, isVirtualApk:${isVirtualApk}, isEmulator${isEmulator}")
//        var loginReq = LoginReq(
//            accessToken = token,
//            thirdType = authType.value,
//            deviceId = getLoginDeviceId(),
//            newDeviceId = newDeviceId,
//            country = getSimCountryCode() ?: "",
//            simulator = isEmulator,
//            virtualApk = isVirtualApk,
//            appsflyerId = appsflyerId,
//            appLang = languageManager?.getLanguageCode() ?: "",
//            systemLang = languageManager?.getSystemLanguageCode() ?: "",
//            simMcc = getSimMmc(),
//            tid = tid,
//            deviceToken = deviceToken,
//            codeVerifier = codeVerifier,
//            inviter = inviteUidCode,
//            shareScene = shareScene
//        )
//        val rlt = loginService.login(
//            loginReq
//        )
//        if (rlt is Rlt.Success) {
//            val res = rlt.data.data
//            if (res != null) {
//                loginSuccess(res, authType)
//                notifyLogin()
//            }
//        }
//        return rlt
        return Rlt.Failed(IError("不支持"))
    }

    override suspend fun testLogin(): Rlt<Res<LoginResult>> {
        Log.d(TAG_ACCOUNT_LOGIN, "testLogin")
        val rlt = loginService.testLogin(TestLoginReq())
        if (rlt is Rlt.Success) {
            val res = rlt.data.data
            if (res != null) {
                loginSuccess(res, ThirdType.GOOGLE)
                notifyLogin()
            }
        }
        return rlt
    }

    private suspend fun googleLogin(token: String): Rlt<Res<LoginResult>> {
        Log.d(TAG_ACCOUNT_LOGIN, "googleLogin, token:$token")
        val rlt = loginService.googleLogin(
            GoogleLoginReq(
                token = token
            )
        )
        if (rlt is Rlt.Success) {
            val res = rlt.data.data
            if (res != null) {
                loginSuccess(res, ThirdType.GOOGLE)
                notifyLogin()
            }
        }
        return rlt
    }


    private fun loginSuccess(result: LoginResult, loginType: ThirdType) {
        val userInfo = result.userInfo
        AppPref.deviceLogined = true
        isLogin = true
        uid = userInfo.uid
        token = result.token
        AppPref.refreshToken = result.token
        ProfileModule.setMyUserInfo(userInfo)
        AccountLocalService.loginType = loginType.value
    }

    override fun getLoginDeviceId(): String {
        val gaId = App.instance.googleService.getGAId()
        if (gaId.isEmpty()) {
            return App.instance.deviceIdService.getDeviceId() ?: ""
        }
        return gaId
    }

    override fun logout(toLogin: Boolean?) {
        isLogin = false
        uid = ""
        token = ""
        isNewRegister = false
        // 置空拉新/邀请相关的参数
        inviteUidCode = null
        inviteRoomIdCode = null
        shareScene = null

        LogoutCleaner.clean()

        notifyLogout()
        if (toLogin == true) {
            if (isCurrentLoginActivity()) {
                return
            }
            Router.build(AppUtil.appContext, Account.Login.PATH)
                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
                .start()
        }
    }

    override fun notifyLogin() {
        dispatch { it.onLogin() }
    }

    override fun notifyLogout() {
        dispatch { it.onLogout() }
    }

    override fun deleteAccount() {
        // TODO: 删除账号
    }

    override fun refreshToken() {
        launch {
            suspendRefreshToken()
        }
    }

    private suspend fun suspendRefreshToken(): Rlt<Any> {
        if (!handlingRefreshToken.compareAndSet(false, true)) {
            return Rlt.Failed(AccountErrorTokenRefreshing())
        }

        if (AppPref.refreshToken.isEmpty()) {
            withContext(Dispatcher.UI) {
                logout(false)
                handleKickOut(UserKickReason.REASON_LOCAL_KICK_TOKEN_EXPIRE)
            }
            handlingRefreshToken.set(false)
            return Rlt.Failed(AccountErrorRefreshTokenEmpty())
        }

        var refreshTokenSuccess = false
        var failedRlt = Rlt.Failed(IError())
        loop@ for (i in 1..3) {

            // 期间可能已经退出登录
            if (AppPref.refreshToken.isEmpty()) {
                break@loop
            }

            val rlt = loginService.refreshToken()
            Log.d(TAG_ACCOUNT_LOGIN, "refresh token(${i}), $rlt")
            when (rlt) {
                is Rlt.Success -> {
//                    val newToken = rlt.data.data
//                    if (newToken.isNullOrEmpty()) {
//                        continue@loop
//                    }
                    refreshTokenSuccess = true
//                    token = newToken
//                    Log.d(TAG_ACCOUNT_LOGIN, "refresh token success, new Token:${newToken}")
                    Log.d(TAG_ACCOUNT_LOGIN, "refresh token success")
                    break@loop
                }

                is Rlt.Failed -> {
                    failedRlt = rlt
                }
            }
        }
        handlingRefreshToken.set(false)
        if (refreshTokenSuccess) {
            return Rlt.Success(true)
        }
        return failedRlt
    }

    override fun onTokenExpire() {
        launch {
            when (val refreshTokenRlt = suspendRefreshToken()) {
                is Rlt.Success -> {
                    //ntd.
                }

                is Rlt.Failed -> {
                    withContext(Dispatcher.UI) {
                        logout(false)
                        handleKickOut(UserKickReason.REASON_LOCAL_KICK_TOKEN_EXPIRE)
                    }
                }
            }
        }
    }

    override fun setIsNewRegister(isNew: Boolean) {
        isNewRegister = isNew
    }

    override fun isNewRegister(): Boolean {
        return isNewRegister
    }

    override fun checkRemoteVirtualAppConfig() {
        launch {
            val block = App.instance.securityService.checkRemoteVirtualAppConfig()
            if (block) {
                logout(true)
            }
        }
    }


    override suspend fun fetchAccountInfo(): Rlt<List<AccountInfo>> {
//        val rlt = loginService.fetchAccountInfo()
//        if (rlt is Rlt.Success) {
//            val res = rlt.data.data
//            if (res != null) {
//                return Rlt.Success(res)
//            }
//        }
        return Rlt.Failed(CommonDataNullError())
    }
}

