package com.ccwangluo.accelerator.utils

import android.annotation.SuppressLint
import android.content.Context
import android.os.RemoteException
import androidx.activity.result.ActivityResultLauncher
import androidx.lifecycle.lifecycleScope
import com.ccnet.acc.NetworkAdapter
import com.ccwangluo.accelerator.model.Game
import com.ccwangluo.accelerator.model.GameInfo
import com.ccwangluo.accelerator.model.NetState
import com.ccwangluo.accelerator.ui.dialog.CommonDialog
import com.ccwangluo.accelerator.utils.datareport.DataRePortUtils
import com.ccwangluo.accelerator.utils.http.HttpGo
import com.github.shadowsocks.Core
import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.ShadowsocksConnection
import com.github.shadowsocks.aidl.TrafficStats
import com.github.shadowsocks.bg.AuthManager
import com.github.shadowsocks.bg.AuthManager.ACC_TIME
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.preference.DataStore
import com.hjq.toast.ToastUtils
import com.xuexiang.xpage.base.XPageActivity
import com.xuexiang.xpage.base.XPageFragment
import com.xuexiang.xutil.common.StringUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import kotlin.math.roundToInt


/**
 * 加速功能工具类
 */
@SuppressLint("StaticFieldLeak")
object AcceleratorUtils {

    private val connection = ShadowsocksConnection(true)

    private lateinit var connect: ActivityResultLauncher<Void?>

    // service
    var state = BaseService.State.Idle
        private set

    private lateinit var context: XPageActivity

    //游戏
    var game: GameInfo? = null

    private val stateListener: (BaseService.State) -> Unit = { state ->
        networkStatsListener(state, getAccTime(), netState)
    }

    private var networkStatsListener: (BaseService.State, Long, NetState?) -> Unit = { _, _, _ ->
    }

    var vipExpireListener: () -> Unit = { ->

    }

    var netState = NetState(-1, -1, "100")

    fun getGameList(xPageFragment: XPageFragment, callback: (Boolean) -> Unit) {
        game?.let {
            callback(true)
        } ?: let {
            xPageFragment.lifecycleScope.launch(Dispatchers.IO) {
                val res = HttpGo.getSync<Game>("/api/new/game/list?id=1&page=1&size=1")
                res?.let {
                    game = it.data?.list?.get(0)
                    withContext(Dispatchers.Main) {
                        callback(true)
                    }
                    game?.let { gameInfo ->
                        AuthManager.gameId = gameInfo.id.toString()
                    }
                }
            }
        }

    }

    fun initContext(context: XPageActivity, connect: ActivityResultLauncher<Void?>) {
        this.context = context
        this.connect = connect
        NetworkAdapter.initNetworks(context)
        ProfileManager.ensureNotEmpty()
        context.lifecycleScope.launch(Dispatchers.IO) {
            while (true) {
                if (state == BaseService.State.Connected) {
                    netState.preNetDelay =
                        NetUtils.tcpPing(DataStore.pingAccHost, DataStore.pingAccPort)
                            .toInt()
                    LoginUtils.getUserHasTimer { haveTime ->
                        if (!haveTime) { //没有加速时长关闭服务
                            stopAccelerator()
                        }
                    }
                    netState.accNetDelay =
                        if (netState.accNetDelay > netState.preNetDelay && netState.preNetDelay != -1) {
                            netState.preNetDelay
                        } else {
                            netState.accNetDelay
                        }
                    netState.lossRate = if (netState.accNetTotal != 0) {
                        (netState.accNetLoss.toFloat() / netState.accNetTotal * 100).roundToInt()
                            .toString()
                    } else {
                        "0"
                    }
                    networkStatsListener(state, getAccTime(), netState)
                } else {
                    networkStatsListener(state, getAccTime(), netState)
                }
                delay(1000)
            }
        }
    }


    fun initConnect(context: Context) {
        connection.connect(context, shadowsocksConnection)
    }

    fun checkVpn(context: Context) {
        if (AuthManager.Last_ACC_TIme == 0L || System.currentTimeMillis() - AuthManager.Last_ACC_TIme > 2 * 3600 * 1000) {
            return
        }
        if (SysUtils.isVpn(context) && state != BaseService.State.Connected) {
            AuthManager.Last_ACC_TIme = 0L
            CommonDialog(context).setTitle("VPN被挤占")
                .setContent("请确保已关闭其他加速器,并未开起任何游戏空间等类似功能")
                .setBtnLeft("取消") {

                }.setBtnRight("我知道了") {

                }.show<CommonDialog>()
            return
        }
    }

    fun startAccelerator(xPageFragment: XPageFragment) {
        game?.let {
            initAuthProfile(xPageFragment)
            val serverPort = it.boosterServer.split(":")
            DataStore.pingAccHost = serverPort[0]
            DataStore.pingAccPort = serverPort[1].toInt()
        }
    }

    private fun initAuthProfile(xPageFragment: XPageFragment) {
        xPageFragment.lifecycleScope.launch(Dispatchers.IO) {
            val profileId = 1L
            val profile = ProfileManager.getProfile(profileId) ?: Profile()
            profile.proxyApps = true
            val proxyGames = mutableSetOf(
//                    "com.android.chrome",
                "com.example.myapplication",
                "com.riotgames.league.wildrifttw",
                "com.activision.callofduty.shooter",
                "com.pubg.krmobile",
            )
            game?.packageName?.let { proxyGames.add(it) }
            game?.boosterPackageName?.split(",")?.forEach {
                if (!StringUtils.isEmpty(it)) {
                    proxyGames.add(it)
                }
            }
//            proxyGames.addAll(profile.individual.split("\n"))
            profile.individual = proxyGames.joinToString("\n")
            profile.route = Acl.BYPASS_LAN
            profile.password = "barfoo!"
            profile.method = "none"
            profile.beatsInterval = 10
            withContext(Dispatchers.Main) {
                ProfileManager.updateProfile(profile)
                connect.launch(null)
            }
        }

    }

    fun registerStateListener(listener: (BaseService.State, Long, NetState?) -> Unit) {
        networkStatsListener = listener
        networkStatsListener(state, getAccTime(), null)
    }

    fun unRegisterStateListener() {
        networkStatsListener = { _, _, _ -> }
    }

    fun registerVipExpireListener(listener: () -> Unit) {
        vipExpireListener = listener
    }

    fun unRegisterVipExpireListener() {
        vipExpireListener = { ->

        }
    }


    fun stopAccelerator() {
        Core.stopService()
    }

    private val shadowsocksConnection = object : ShadowsocksConnection.Callback {
        override fun stateChanged(state: BaseService.State, profileName: String?, msg: String?) {
            AcceleratorUtils.state = state
            stateListener(state)
            if (state == BaseService.State.Stopped && !msg.isNullOrBlank()) {
                DataRePortUtils.report(
                    "st_speed_result",
                    mapOf("result" to 0, "cause" to 3.toString())
                )
                if ("vip到期".equals(msg) || (msg != null && msg.startsWith("vip已到期"))) {
                    vipExpireListener()
                } else {
                    stopAccelerator()
                    ToastUtils.show(msg)
                }
            }

            if (state == BaseService.State.Connected && getAccTime() < 100) {
                DataRePortUtils.report("st_speed_result", mapOf("result" to 1))
            }
        }

        override fun onServiceConnected(service: IShadowsocksService) {
            state = try {
                BaseService.State.values()[service.state]
            } catch (_: RemoteException) {
                BaseService.State.Idle
            }
            stateListener(state)
        }

        override fun onBinderDied() {
            connection.disconnect(context)
            connection.connect(context, this)
        }

        override fun trafficUpdated(profileId: Long, stats: TrafficStats) {
            netState.accNetDelay = stats.latency
            netState.accNetTotal++
            if (stats.latency == -1) {
                netState.accNetLoss++
            }
        }
    }

    fun getAccTime(): Long {
        return if (ACC_TIME == 0L) 0 else System.currentTimeMillis() - ACC_TIME
    }

    fun onStart() {
        connection.bandwidthTimeout = 500
    }


    fun onStop() {
        connection.bandwidthTimeout = 0
    }

    fun onDestroy(context: Context) {
        connection.disconnect(context)
    }


}