package com.adealink.weparty.im.manager.login

import android.app.Application
import com.adealink.frame.aab.util.getCompatString
import com.adealink.frame.base.AppBase
import com.adealink.frame.base.CommonDataNullError
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.network.util.removeNetworkCallbacks
import com.adealink.frame.network.util.runNetworkThread
import com.adealink.frame.util.AppUtil
import com.adealink.weparty.App
import com.adealink.weparty.commonui.ext.isFailure
import com.adealink.weparty.commonui.toast.util.showToast
import com.adealink.weparty.im.R
import com.adealink.weparty.im.constant.TAG_IM_LOGIN
import com.adealink.weparty.im.data.UserInfo.Companion.loginUserInfo
import com.adealink.weparty.im.datasource.remote.IMHttpService
import com.adealink.weparty.im.manager.LoginWrapper
import com.adealink.weparty.im.util.TUIUtils
import com.adealink.weparty.module.account.AccountModule
import com.adealink.weparty.module.account.data.UserKickReason
import com.adealink.weparty.module.im.IMConfig
import com.adealink.weparty.module.profile.ProfileModule
import com.adealink.weparty.module.profile.data.Gender
import com.adealink.weparty.module.profile.data.UserInfo
import com.tencent.imsdk.v2.V2TIMCallback
import com.tencent.imsdk.v2.V2TIMManager
import com.tencent.imsdk.v2.V2TIMUserFullInfo
import com.tencent.qcloud.tuicore.TUIConfig
import com.tencent.qcloud.tuicore.TUILogin
import com.tencent.qcloud.tuicore.interfaces.TUICallback
import com.tencent.qcloud.tuicore.interfaces.TUILoginConfig
import com.tencent.qcloud.tuicore.interfaces.TUILoginListener
import kotlinx.coroutines.launch

val imLoginManager: ILoginManager by lazy { LoginManager() }

class LoginManager : BaseFrame<ILoginListener>(),
    ILoginManager,
    com.adealink.weparty.module.account.ILoginListener {

    companion object {
        private const val PING_DEFAULT_INTERVAL = 5 * 1000L
    }

    private var checkLoginInterval = PING_DEFAULT_INTERVAL
    private val checkLoginRunnable by lazy {
        Runnable {
            reLogin()
            startCheckLogin(checkLoginInterval)
        }
    }

    private fun startCheckLogin(interval: Long = checkLoginInterval) {
        Log.d(TAG_IM_LOGIN, "startCheckLogin, pingInterval:$interval")
        removeNetworkCallbacks(checkLoginRunnable)
        runNetworkThread(checkLoginRunnable, interval)
    }

    private fun stopCheck() {
        removeNetworkCallbacks(checkLoginRunnable)
    }

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

    override fun init(application: Application) {
        AccountModule.registerListener(this)
        login()
    }

    override fun onLogin() {
        Log.d(TAG_IM_LOGIN, "onLogin")
        login()
        startCheckLogin()
    }

    override fun onLogout() {
        Log.d(TAG_IM_LOGIN, "onLogout")
        if (isLogin()) {
            logout()
        }
        stopCheck()
    }

    private fun reLogin() {
        login(true)
    }

    private var isIMLogin = false
    override fun login(reLogin: Boolean) {
        launch {
            if (isIMLogin) {
                Log.d(TAG_IM_LOGIN, "handleLogin, return, for im is login-ing")
                return@launch
            }
            if (!AccountModule.isLogin()) {
                Log.d(TAG_IM_LOGIN, "login return, Account is not Login")
                return@launch
            }
            if (TUILogin.isUserLogined()) {
                Log.d(TAG_IM_LOGIN, "login return, TUILogin.isUserLogin")
                return@launch
            }
            val uid = AccountModule.uid
            if (uid.isEmpty()) {
                Log.e(TAG_IM_LOGIN, "handleLogin fail, for $uid is invalid.")
                return@launch
            }

            val userSignRlt = getUserIMSign()
            if (userSignRlt.isFailure) {
                Log.d(TAG_IM_LOGIN, "handleLogin, getUserIMSign fail, $userSignRlt")
                return@launch
            }
            val userSign = (userSignRlt as Rlt.Success).data
            if (!AppBase.isRelease) {
                Log.d(TAG_IM_LOGIN, "handleLogin, getUserIMSign: $userSign")
            }
            val tuiLoginConfig: TUILoginConfig = TUIUtils.getLoginConfig()
            isIMLogin = true
            LoginWrapper.loginIMSDK(
                AppUtil.appContext,
                IMConfig.APP_ID,
                uid,
                userSign, tuiLoginConfig,
                object : TUICallback() {
                    override fun onSuccess() {
                        isIMLogin = false
                        Log.i(TAG_IM_LOGIN, "login onSuccess, uid: $uid")
                        TUILogin.addLoginListener(mLoginListener)

                        updateSelfUserInfo(ProfileModule.getMyUserInfo())
                    }

                    override fun onError(errorCode: Int, errorMessage: String?) {
                        isIMLogin = false
                        Log.e(
                            TAG_IM_LOGIN,
                            "login fail errorCode: $errorCode errorMessage:$errorMessage"
                        )
                        showToast(
                            getCompatString(
                                R.string.im_login_fail,
                                errorCode.toString(),
                                errorMessage ?: ""
                            )
                        )
                    }
                })
        }
    }

    private suspend fun getUserIMSign(): Rlt<String> {
        val rlt = imHttpService.imUserSign()
        when (rlt) {
            is Rlt.Failed -> {
                return rlt
            }

            is Rlt.Success -> {
                val sign = rlt.data.data
                if (sign.isNullOrEmpty()) {
                    return Rlt.Failed(CommonDataNullError())
                }
                return Rlt.Success(sign)
            }
        }
    }

    override fun isLogin(): Boolean {
        return TUILogin.isUserLogined()
    }

    override fun updateSelfUserInfo(userInfo: UserInfo?) {
        userInfo ?: return
        launch {
            TUIConfig.setSelfNickName(userInfo.nickName)
            TUIConfig.setSelfFaceUrl(userInfo.avatar)

            val v2TIMUserFullInfo = V2TIMUserFullInfo()
            v2TIMUserFullInfo.faceUrl = userInfo.avatar
            v2TIMUserFullInfo.setNickname(userInfo.nickName)
            v2TIMUserFullInfo.birthday = userInfo.birthday ?: 0
            v2TIMUserFullInfo.gender = userInfo.gender ?: Gender.UNKNOWN.gender
            V2TIMManager.getInstance().setSelfInfo(v2TIMUserFullInfo, object : V2TIMCallback {
                override fun onError(code: Int, desc: String?) {
                    Log.e(TAG_IM_LOGIN, "updateSelfUserInfo fail, code:$code, desc:$desc")
                }

                override fun onSuccess() {
                    Log.d(TAG_IM_LOGIN, "updateSelfUserInfo success")
                    TUIConfig.setSelfNickName(userInfo.nickName)
                    TUIConfig.setSelfFaceUrl(userInfo.avatar)
                }
            })
        }
    }

    override fun checkLogin() {
        launch {
            val isLogin = isLogin()
            if (isLogin) {
                Log.d(TAG_IM_LOGIN, "checkLogin return, for user already login")
                return@launch
            }
            reLogin()
        }
    }


    private fun logout() {
        try {
            TUILogin.logout(object : TUICallback() {
                override fun onSuccess() {
                    Log.i(TAG_IM_LOGIN, "logout success")
                    TUILogin.removeLoginListener(mLoginListener)
                }

                override fun onError(errorCode: Int, errorMessage: String) {
                    Log.e(
                        TAG_IM_LOGIN,
                        "logout failed, errorCode: $errorCode , errorMessage: $errorMessage"
                    )
                }
            })
        } catch (e: Exception) {
            Log.e(TAG_IM_LOGIN, "logout failed with exception: ${e.message}", e)
        }

    }

    private val mLoginListener: TUILoginListener = object : TUILoginListener() {
        override fun onKickedOffline() {
            super.onKickedOffline()
            Log.i(TAG_IM_LOGIN, "You have been kicked off the line")
            loginUserInfo.cleanUserInfo()
            logout()
            AccountModule.onKickedOffline(UserKickReason.REASON_KICK_ONLINE_BY_MULTIPOINT_LOGIN)
        }

        override fun onUserSigExpired() {
            super.onUserSigExpired()
            Log.i(TAG_IM_LOGIN, "Your user signature information has expired")
            reLogin()
        }
    }
}