package com.gh.gamecenter.accelerator.provider

import android.app.Application
import androidx.lifecycle.LiveData
import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData
import com.gh.gamecenter.common.utils.EnvHelper
import com.gh.gamecenter.core.HaloApp
import com.gh.gamecenter.core.callback.AccelerateState
import com.gh.gamecenter.core.callback.OnAccelerateListener
import com.gh.gamecenter.core.provider.IAcceleratorDataHolderProvider
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.feature.entity.AcctGameInfo
import com.gh.gamecenter.feature.entity.VipEntity
import com.gh.gamecenter.feature.utils.NewFlatLogUtils
import com.lightgame.utils.Utils
import com.qeeyou.qyvpn.QyAccelerator
import com.qeeyou.qyvpn.bean.QyAcctGameInfo
import com.qeeyou.qyvpn.utils.OnQyAccAssistantSimpleListener
import com.qeeyou.qyvpn.utils.OnQyAccelerateListener
import com.qeeyou.qyvpn.utils.QyAccConfig
import com.therouter.TheRouter
import java.io.File

/**
 * 单例模式，可以用户保存一些加速器全局状态信息
 */
@com.therouter.inject.ServiceProvider
class AcceleratorProviderImpl : IAcceleratorProvider {
    private var _token = ""

    private val initResults = arrayListOf<String>()

    // 根据包名回调
    private val listeners = hashMapOf<String, OnAccelerateListener>()

    // 所有包名都回调(pkgName.isBlank())
    private val allListener = mutableSetOf<OnAccelerateListener>()
    private var curAcctGameInfo: AcctGameInfo? = null

    // 当游戏加速状态发生变化时，通过这个LiveData通知外界;第一个String:加速成功的包名，第二个String:恢复正常状态的包名
    private val gameStatusEventLiveData = NonStickyMutableLiveData<Pair<String, String>>()

    private var _vipEntity: VipEntity? = null

    private val qyListener = object : OnQyAccelerateListener {
        override fun onAccCurrentProgress(progress: Int, curGamePkgName: String?, curGameZoneFlag: String?) {
            listeners[curGamePkgName]?.onProgress(progress, curGamePkgName, curGameZoneFlag)
            allListener.forEach {
                it.onProgress(progress, curGamePkgName, curGameZoneFlag)
            }
        }

        override fun onAccCurrentStatus(
            status: QyAccelerator.QyStatus,
            curGamePkgName: String?,
            curGameZoneFlag: String?,
            eventCode: Int,
            eventMsg: String?,
            extraParam: Any?
        ) {
            Utils.log(LOG_TAG, "onAccCurrentStatus:$status -- code:$eventCode -- msg:$eventMsg")
            val state = when (status) {
                QyAccelerator.QyStatus.AccNormal -> {
                    val norPkgName = curGamePkgName ?: ""
                    gameStatusEventLiveData.value = "" to norPkgName
                    AccelerateState.Normal(eventCode)
                }

                QyAccelerator.QyStatus.AccStarting -> AccelerateState.Starting(eventCode)
                QyAccelerator.QyStatus.AccSuccess -> {
                    val curPkgName = curGamePkgName ?: ""
                    val norPkgName = gameStatusEventLiveData.value?.first ?: ""
                    gameStatusEventLiveData.value = curPkgName to norPkgName
                    AccelerateState.Success(curAcctGameInfo, eventCode)
                }

                QyAccelerator.QyStatus.AccFailure -> {
                    AccelerateState.Failure(eventCode)
                }

                QyAccelerator.QyStatus.AccOkStopping -> AccelerateState.OkStopping(eventCode)
                QyAccelerator.QyStatus.AccErrStopping -> AccelerateState.ErrStopping(eventCode)
            }
            listeners[curGamePkgName]?.onStateChanged(state)
            allListener.forEach {
                it.onStateChanged(state)
            }
        }

        override fun onAccEventCallBack(
            eventCode: Int,
            eventMsg: String?,
            curGamePkgName: String?,
            curGameZoneFlag: String?
        ) = Unit

        override fun onAccExtraInfoEvent(
            eventFlag: QyAccelerator.QyExtra,
            extraInfo: Any?,
            curGamePkgName: String?,
            curGameZoneFlag: String?
        ) = ""
    }

    override fun init(isDev: Boolean, application: Application, version: String) {
        Utils.log(LOG_TAG, "init:$version --isDev:$isDev")
        val qyAccConfigBuilder = QyAccConfig.Builder().setAppId("QyAccSdk")
            .setDebug(isDev)
            .setAppVersion(version)
            .setServerAddressEnv(if (isDev) QyAccConfig.ServerAddressEnv.Debug else QyAccConfig.ServerAddressEnv.Release)
            .build()
        QyAccelerator.getInstance().init(application, qyAccConfigBuilder, QyAccelerator.QyAccStrategy.HaloRing, object :
            OnQyAccAssistantSimpleListener() {
            override fun onExecLifecycleInitFun(isEnter: Boolean) {
                super.onExecLifecycleInitFun(isEnter)
                Utils.log(LOG_TAG, "onExecLifecycleInitFun:$isEnter")
                initResults.add("onExecLifecycleInitFun:$isEnter")
            }
        })
        QyAccelerator.getInstance().bindQyAccRelatedListener(qyListener)
        QyAccelerator.getInstance().switchAccLogCanUpload(true)
    }

    override fun setQyUserToken(token: String, userId: String, finished: (() -> Unit)) {
        Utils.log(LOG_TAG, "setQyUserToken")
        if (_token == token) {
            // 避免外部多次设置相同的token
            finished()
            return
        }
        fun setToken() {
            QyAccelerator.getInstance().setQyUserToken(token, setResultCallback = { isSuccess, errMsg ->
                Utils.log(LOG_TAG, "setQyUserToken:$token --isSuccess:$isSuccess --errMsg:$errMsg")
                if (isSuccess) {
                    _token = token
                    loadQyUserPermissionData(userId, finished)
                } else {
                    finished()
                    // 将setToken错误事件上报的火山云，便于后期分析原因
                    NewFlatLogUtils.logAcceleratorSetTokenError(initResults, errMsg ?: "")
                }
            })

        }
        if (QyAccelerator.getInstance().checkApplicationContextIsInit()) {
            setToken()
        } else {
            // 初始化失败，再次初始化之后在setToken
            val ghVersionName = TheRouter.get(IAcceleratorDataHolderProvider::class.java)?.getGhVersionName() ?: ""
            init(EnvHelper.isDevEnv, HaloApp.getInstance(), ghVersionName)
            // 不管初始化成功还是失败，都需要再次setToken,如果失败，正常上报失败日志
            setToken()
        }

    }

    override fun deleteQyUserToken(): Boolean {
        Utils.log(LOG_TAG, "deleteQyUserToken")
        if (isCurAccSuccess()) {
            stopQyGameAccelerate("退出登录!")
        }
        // 退出登录的时候才会调用
        val isDeleted = QyAccelerator.getInstance().delQyUserToken()
        _token = ""
        listeners.clear()
        allListener.clear()
        initResults.clear()
        return isDeleted
    }

    override fun startQyGameAccelerate(gameId: String, pkgName: String, zoneInfo: Any) {
        QyAccelerator.getInstance().clearAllAccLogFile()
        Utils.log(LOG_TAG, "startQyGameAccelerate:$zoneInfo")
        if (zoneInfo is AcctGameInfo.ZoneInfo) {
            val qyAcctGameInfo = QyAcctGameInfo(
                pkgName,
                zoneInfo.id.toString()
            )
            curAcctGameInfo = AcctGameInfo(gameId, pkgName, zoneInfo)
            QyAccelerator.getInstance().startQyGameAccelerate(qyAcctGameInfo)
        }
    }

    override fun stopQyGameAccelerate(appLayerCallStopMsg: String?): Boolean {
        Utils.log(LOG_TAG, "stopQyGameAccelerate:$appLayerCallStopMsg")
        return QyAccelerator.getInstance().stopQyGameAccelerate(appLayerCallStopMsg)
    }

    override fun bindAccRelatedListener(pkgName: String, listener: OnAccelerateListener) {
        if (pkgName.isBlank()) {
            allListener.add(listener)
        } else {
            listeners[pkgName] = listener
        }
    }

    override fun unBindAccRelatedListener(listener: OnAccelerateListener) {
        listeners.values.remove(listener)
        allListener.remove(listener)
    }

    override fun isCurAccSuccess(): Boolean {
        return QyAccelerator.getInstance().isCurAccSuccess()
    }

    override fun getAccLogFileStorageList(): List<File>? {
        return QyAccelerator.getInstance().getAccLogFileStorageList()
    }

    override fun getGameStatusEventLiveData(): LiveData<Pair<String, String>> {
        return gameStatusEventLiveData
    }

    override fun loadQyUserPermissionData(userId: String, finished: (() -> Unit)?) {
        val iAcceleratorDataHolderProvider = TheRouter.get(IAcceleratorDataHolderProvider::class.java)
        if (iAcceleratorDataHolderProvider != null) {
            iAcceleratorDataHolderProvider.loadVipEntityFromGh(userId) { data ->
                val vipEntity = if (data is VipEntity) {
                    _vipEntity = data
                    data
                } else {
                    _vipEntity
                }
                if (vipEntity != null) {
                    iAcceleratorDataHolderProvider.updateVipEntity(vipEntity)
                }
                finished?.invoke()
            }
        } else {
            finished?.invoke()
        }

    }

    override fun hasToken(): Boolean = _token.isNotBlank()

    companion object {
        private const val LOG_TAG = "AcceleratorProviderImpl"
        private const val SENTRY_EVENT_ID = "ACCELERATOR_SET_TOKEN_ERROR"
        private const val KEY_SET_TOKEN_ERROR_MESSAGE = "set_token_error"
        private const val KEY_ACC_FAILURE_ERROR = "key_acc_failure_error"

    }

}