package com.joyful.euphoria.board.environment

import android.annotation.SuppressLint
import android.app.Activity
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.telephony.TelephonyManager
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.applock.filemanager.magiclock.control.MagicLock
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.google.gson.JsonObject
import com.joyful.euphoria.board.R
import com.joyful.euphoria.board.databinding.ActivityMain2Binding
import com.joyful.euphoria.board.environment.ad.AdShowFailed
import com.joyful.euphoria.board.environment.ad.AdsInsUtil
import com.joyful.euphoria.board.environment.ad.InstAdCacheManager
import com.joyful.euphoria.board.environment.ad.LoadListener
import com.joyful.euphoria.board.environment.ad.ShowListener
import com.joyful.euphoria.board.environment.hy.AppLifecycleTracker
import com.joyful.euphoria.board.environment.hy.ConfigCallback
import com.joyful.euphoria.board.environment.hy.IdProvider
import com.joyful.euphoria.board.environment.hy.MyConfigUtil
import com.joyful.euphoria.board.environment.hy.SimIdProvider
import com.joyful.euphoria.board.environment.hy.TimeoutManager
import com.joyful.euphoria.board.environment.hy.TimeoutTask
import com.joyful.euphoria.board.environment.hy.getLocalIpAddress
import com.tradplus.ads.base.bean.TPAdInfo
import com.tradplus.ads.open.TradPlusSdk
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Response
import org.json.JSONObject
import java.io.IOException
import java.math.BigDecimal
import java.math.RoundingMode
import java.util.Locale
import java.util.Random
import java.util.Timer
import java.util.TimerTask
import java.util.UUID
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine


@SuppressLint("WrongConstant")
class MainActivity2 : AppCompatActivity() {
    private lateinit var binding: ActivityMain2Binding
    private var loadAdNumber = 0//load广告计数
    private var timer: Timer? = null
    private val adPlace: MutableList<String> = ArrayList()//可以被show的广告集合
    private var loadAndShowAdNumber = 0//load后并且可以进行show的广告计数
    private val loadJson = JsonObject()//需要上传的load日志json
    private val showJson = JsonObject()//需要上传的show日志json
    private val viewJson = JsonObject()//展示在刷刷包上的json，选择了一些数据来展示。
    private var quantity = ""//可以被load的广告次数
    private var ecpmCool = ""//最高的ecpm配置
    private var ecpmLow = ""//最低的ecpm配置
    private var clickThroughRate = 80
    private val gaIdError = "00000000-0000-0000-0000-000000000000"
    private val loadingAds: MutableSet<String> = mutableSetOf()// 用来跟踪正在加载的广告
    private var startInit = false//是否已经到达初始化广告
    private var shelfNumber = "123"
    private var devicesID = ""
    private val appStartJson = JsonObject()
    private var dataId = 0L
    private var simId = 0L
    private val aidlClient = AIDLClient.instance
    private var isProcessComplete = true //流程是否完毕
    private var remoteIp = "0.0.0.0"//上传到服务的IP

    private val onAdShownLiveData = MutableLiveData<Boolean>()
    private val onAdShowFailedLiveData = MutableLiveData<Boolean>()
    private val onAdClosedLiveData = MutableLiveData<Boolean>()

    @SuppressLint("MissingInflatedId", "SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMain2Binding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.title.text = "TradPlus(1月16日)-${getString(R.string.app_name)}"
        // 异步获取 IP，不影响主流程
        lifecycleScope.launch {
            remoteIp = getPublicIpAddress()
            loadJson.addProperty("remoteIp", remoteIp)//远程IP
            showJson.addProperty("remoteIp", remoteIp)//远程IP
        }
        TradPlusSdk.initSdk(this, "0050AC0F82A15B4B5CCEC0E7A5B07A11")
        TradPlusSdk.setTradPlusInitListener {
            appendLoadingTxt("初始化成功")
            lifecycle.addObserver(AppLifecycleTracker)
            //初始化aidl连接
            aidlClient.initConnection()
            //绑定AIDL服务
            aidlClient.connectService(this@MainActivity2)
            aidlClient.connectCompleteLiveData.observeForever(connectCompleteObserver)

            aidlClient.paramCompleteLiveData.observeForever(paramCompleteObserver)
            aidlClient.clickAdCompleteLiveData.observeForever(clickAdCompleteObserver)

            onAdShownLiveData.observeForever(onAdShownObserver)
            onAdShowFailedLiveData.observeForever(onAdShowFailedObserver)
            onAdClosedLiveData.observeForever(onAdCloseObserver)
        }
    }

    private val connectCompleteObserver = Observer<Boolean> {
        if (it) {
            appendLoadingTxt("CP控制器连接成功，进行初始化配置")
            aidlClient.sendBrushMiss()
            //初始化配置
            initConfig()
            //初始化屏幕点击范围
            magicLockInit()
        } else {
            appendLoadingTxt("CP控制器连接失败，检查是否安装了正确的软件")
        }
    }

    private val paramCompleteObserver = Observer<Boolean> {
        TimeoutManager.cancelTimeout(TimeoutTask.PARAM_CHANGE)
        appendLoadingTxt("参数修改完成")
        Log.d("ocean-brush", "MainActivity 参数修改操作完成->$it")
        if (it) {
            aidlClient.sendResetApp(packageName)
        } else {
            appendLoadingTxt("参数修改失败，等待${paramTimeLeft}秒再次进行参数修改")
            startParamCountdown()
        }
    }

    private val clickAdCompleteObserver = Observer<Boolean> {
        Log.d("ocean-brush", "MainActivity 监听到点击广告指令完成")
        if (it) {
            if (AppLifecycleTracker.isMainActivityVisible) {
                Log.d(
                    "ocean-brush",
                    "MainActivity 成功回到前台，取消点击超时任务，并置 isProcessComplete = true"
                )
                TimeoutManager.cancelTimeout(TimeoutTask.CLICK_AD)
                isProcessComplete = true
            } else {
                Log.d("ocean-brush", "MainActivity 但是没有回到前台，进行修改参数重置")
                aidlClient.sendChangeParameters(packageName)
            }
        } else {
            Log.d("ocean-brush", "MainActivity 但是intent=null，进行修改参数重置")
            aidlClient.sendChangeParameters(packageName)
        }
    }

    private val onAdShownObserver = Observer<Boolean> {
        Log.d("ocean-brush", "MainActivity 监听到广告展示成功")
        TimeoutManager.cancelTimeout(TimeoutTask.SHOW_AD)
        val isSendClick = aidlClient.sendClickAd(clickThroughRate, packageName)
        if (isSendClick) {//指令发送成功
            //广告展示后，启动广告关闭超时任务
            TimeoutManager.startTimeout(TimeoutTask.CLOSE_AD) {//十秒
                Log.d("ocean-brush", "超时任务，广告关闭失败，直接进行改参重置")
                aidlClient.sendChangeParameters(packageName)
            }
            //发送点击广告指令后，启动点击广告的超时任务
            TimeoutManager.startTimeout(TimeoutTask.CLICK_AD) {
                Log.d("ocean-brush", "超时任务，广告点击流程没有回来，直接进行重置")
                aidlClient.sendChangeParameters(packageName)
            }
        }
    }

    private val onAdShowFailedObserver = Observer<Boolean> {
        Log.d("ocean-brush", "MainActivity 监听到广告展示失败，直接进行重置")
        TimeoutManager.cancelTimeout(TimeoutTask.SHOW_AD)
        aidlClient.sendChangeParameters(packageName)
    }

    private val onAdCloseObserver = Observer<Boolean> {
        Log.d("ocean-brush", "MainActivity 监听到广告被关闭")
        TimeoutManager.cancelTimeout(TimeoutTask.CLOSE_AD)
    }

    private fun initConfig() {
        aidlClient.sendBrushMiss()
        val fromCpGuise = intent?.getBooleanExtra("EXTRA_FROM_CP_GUISE_RESET", false) ?: false
        if (fromCpGuise) {
            Log.d("ocean-brush", "App2 是从 CP reset 启动的！通知cp知道")
            aidlClient.sendReceiveResetOpenSuccessfully()
        }

        binding.applicationId.text = packageName
        getDeviceIdFromProvider { content, b ->
            appendLoadingTxt("${b}设备ID:$content")
            if (content != null) {
                devicesID = content
            }
        }
        dataId = IdProvider().getId()
        simId = SimIdProvider().getSimId()
        val hookInfo =
            "dataId->$dataId," + "simId->$simId" + "制造商:${Build.MANUFACTURER}," + "型号:${Build.MODEL}," + "国家:${
                getSimCountryIso(this@MainActivity2)
            }," + "MCC:${mcc()}," + "MNC:${mnc()}"
        appendLoadingTxt(hookInfo)
        if (dataId <= 0L) {
            appendLoadingTxt("dataId返回的默认值，hook没生效，修改参数重试")
            startCountdown()
            return
        }
        MyConfigUtil.getConfig(packageName, object : ConfigCallback {
            override fun onResponse(result: String) {
                aidlClient.sendBrushMiss()
                Log.d("ocean-brush", "加载config配置成功")
                Log.d("ocean", "result->${result}")
                val json = JSONObject(result)
                val dataJson = json.optJSONObject("data")
                if (dataJson != null) {
                    quantity = dataJson.optString("quantity")
                    ecpmCool = dataJson.optString("ecpmCool")
                    ecpmLow = dataJson.optString("ecpmLow")
                    clickThroughRate = dataJson.optInt("clickThroughRate")
                    appendLoadingTxt("配置->quantity:${quantity},ecpmCool:${ecpmCool},ecpmLow:${ecpmLow},点击:${clickThroughRate}")
                    getBidJson()
                }
            }

            override fun onFailure(e: IOException) {
                aidlClient.sendBrushMiss()
                Log.d("ocean-brush", "加载config配置失败")
                val message = "message=${e.message}"
                appendLoadingTxt("$message \n Config获取失败，请检查是否在后台配置包名，${timeLeft}秒后将会重置")
                runOnUiThread {
                    startCountdown()
                }
            }
        })
    }

    private fun magicLockInit() {
        aidlClient.sendBrushMiss()
        MagicLock.getInstance(application)
            .addMagicActionListener(object : MagicLock.MagicActionListener {
                override fun insAreaClick() {

                }

                override fun rewardAreaClick() {

                }
            })
        timer = Timer()
        timer!!.schedule(object : TimerTask() {
            override fun run() {
                runOnUiThread {
                    if ((loadAndShowAdNumber <= 0 || adPlace.size <= 0)) {
                        /**
                         * 没有广告的情况
                         * [startInit]广告已经进入过初始化
                         * [isAnyAdLoading]没有广告在loading中
                         * [isProcessComplete]每次流程是否执行完毕
                         * [AppLifecycleTracker.isMainActivityVisible]应用已经恢复到前台展示
                         * 满足条件则进行重置，发送修改参数指令
                         */
                        if (startInit && !isAnyAdLoading() && isProcessComplete && AppLifecycleTracker.isMainActivityVisible) {
                            //更新UI，显示为 true
                            MagicLock.getInstance(application)
                                .refreshStartResetView(this@MainActivity2, true)
                            //发送修改参数指令
                            aidlClient.sendChangeParameters(packageName)
                        }
                    } else {
                        /**
                         * 有广告可以展示
                         * [isProcessComplete]流程已经执行完毕
                         * [AppLifecycleTracker.isMainActivityVisible]应用已经恢复到前台展示
                         * 满足条件发送show指令
                         */
                        if (isProcessComplete && AppLifecycleTracker.isMainActivityVisible) {
                            //开始执行点击流程时，置为false
                            isProcessComplete = false
                            showInsAd()
                            //启动show超时检测，然后在show成功与show失败取消超时任务
                            TimeoutManager.startTimeout(TimeoutTask.SHOW_AD) {
                                //超时都没有show出来则流程重置，让time下次判定可以去show广告
                                isProcessComplete = true
                            }
                            // 开始流程后，启动是否有广告卡住流程的超时任务。100秒
                            TimeoutManager.startTimeout(TimeoutTask.OVERALL_PROCESS) {
                                aidlClient.sendChangeParameters(packageName)
                            }
                        }
                    }
                    MagicLock.getInstance(application)
                        .refreshInsCountView(this@MainActivity2, adPlace.size)
                    //在TimerTask任务中判定流程已经完毕，并且是否回到了mainActivity，回来则取消超时
                    //超过没有回来，则判定为卡住了。
                    if (isProcessComplete && AppLifecycleTracker.isMainActivityVisible) {
                        TimeoutManager.cancelTimeout(TimeoutTask.OVERALL_PROCESS)
                    }
                }
                //发送广告数量
                aidlClient.sendAdsChange(packageName, getInsAdReturnCount())

                //通信cp，用于心跳检测
                aidlClient.sendHeartBeat(packageName)
            }
        }, 2000, 2000)
    }

    // 检查是否有广告在加载中
    fun isAnyAdLoading(): Boolean {
        return loadingAds.isNotEmpty()
    }

    private fun initAd() {
        aidlClient.sendBrushMiss()
        Log.d("ocean-brush", "开始加载三个广告")
        startInit = true
        appendLoadingTxt("开始加载三个广告")
        loadAd(AdsInsUtil.Placement.TOP_ON_AD_ONE)
        loadAd(AdsInsUtil.Placement.TOP_ON_AD_TOW)
        loadAd(AdsInsUtil.Placement.TOP_ON_AD_THREE)
    }

    private fun loadAd(placeId: String) {
        val startLoadTime = System.currentTimeMillis()
        loadingAds.add(placeId)

        loadAdNumber++//广告load计数（进入loadAd方法就进行计数）

        AdsInsUtil.loadAd(this, placeId, object : LoadListener {
            @SuppressLint("DefaultLocale")
            override fun loaded(ad: TPAdInfo) {
                aidlClient.sendBrushMiss()
                val loadedEndTime = System.currentTimeMillis()
                appendLoadingTxt("${placeId}AD加载成功")
                aidlClient.sendAdsChange(packageName, getInsAdReturnCount())
                // 将 ecpm 转换为 BigDecimal 类型，并进行除法运算
                val result = BigDecimal(ad.ecpm.toDouble()).divide(
                    BigDecimal(1000),
                    20,
                    RoundingMode.HALF_UP
                )
                // 将结果转换为字符串表示形式
                val formattedString: String = result.toPlainString()
                Log.d("ocean", "scientificNotation->${formattedString}")
                appendLoadingTxt("${ad.adNetworkId} ecpm->$formattedString")
                Log.d("ocean", "平台->${ad.adNetworkId} ecpm->${formattedString}")
                loadJson.addProperty("succeed", true)//广告加载是否成功
                loadJson.addProperty("loadTime", loadedEndTime - startLoadTime)//加载时间
                loadJson.addProperty("adPlatform", "TradPlus")//广告平台
                loadJson.addProperty("countryCode", ad.format)//国家代码
                loadJson.addProperty("adId", placeId)//广告Id
                loadJson.addProperty("platformResponseTime", "")//平台广告响应时间
                loadJson.addProperty("ecpm", formattedString)//广告单价
                loadJson.addProperty("dsp", ad.adNetworkId)
                loadJson.addProperty("network", ad.adNetworkId)
                loadJson.addProperty("washParam", false)

                //load广告，只有价格大于等于配置的最低值则添加到可以show的广告集合中
                if (formattedString.toFloat() >= ecpmLow.toFloat()) {
                    Log.d("ocean", "onAdLoaded add ->${placeId}")
                    adPlace.add(placeId)
                    loadAndShowAdNumber++
                    loadJson.addProperty("showStatus", "0")
                } else {
                    loadJson.addProperty("showStatus", "-1")
                }

                viewJson.addProperty("广告加载时间", loadedEndTime - startLoadTime)
                viewJson.addProperty("ecpmLow", ecpmLow)
                viewJson.addProperty("ecpm", formattedString)
                viewJson.addProperty("是否满足show", formattedString.toFloat() >= ecpmLow.toFloat())
                appendInfoTxt(viewJson.toString())

                MyConfigUtil.initPostLoadLog(loadJson)

                loadingAds.remove(placeId)
            }

            override fun loadFailed(error: String) {
                aidlClient.sendBrushMiss()
                val loadedEndTime = System.currentTimeMillis()
                loadJson.addProperty("succeed", false)//广告加载是否成功
                loadJson.addProperty("loadTime", loadedEndTime - startLoadTime)//加载时间
                loadJson.addProperty("adPlatform", "TradPlus")//广告平台
                loadJson.addProperty("adId", placeId)//广告Id
                loadJson.addProperty("washParam", false)
                loadJson.addProperty("errorData", error)

                MyConfigUtil.initPostLoadLog(loadJson)

                Log.d("ocean", "error->${error.toString()}")
                aidlClient.sendAdsChange(packageName, getInsAdReturnCount())
                loadingAds.remove(placeId)
                appendLoadingTxt("${placeId}AD加载失败-${error}")
            }
        })
    }

    private val msgSB = StringBuilder()
    private fun appendInfoTxt(msg: String) {
        runOnUiThread {
            msgSB.appendLine(msg)
            binding.infoTv.text = msgSB.toString()
        }
    }

    private val msgLoading = StringBuilder()
    private fun appendLoadingTxt(msg: String) {
        runOnUiThread {
            msgLoading.appendLine(msg)
            binding.loadingTv.text = msgLoading.toString()
        }
    }

    private fun getInsAdReturnCount(): Int {
        return InstAdCacheManager.instance.getLoadedInstCount()
    }

    fun showInsAd() {
        aidlClient.sendBrushMiss()
        Log.d("ocean-brush", "满足条件，开始展示广告")
        //随机
        Log.d("ocean", " show广告集合是否有值：${adPlace.size}")
        if (adPlace.isNotEmpty()) {
            val placeId = Random().nextInt(adPlace.size)
            val place = adPlace[placeId]
            adPlace.remove(place)

            AdsInsUtil.showAd(this, place, object : ShowListener {
                @SuppressLint("DefaultLocale")
                override fun onAdShown(ad: TPAdInfo?) {
                    aidlClient.sendBrushMiss()
                    Handler(Looper.getMainLooper()).post {
                        onAdShownLiveData.value = true
                    }
                    // 将 ecpm 转换为 BigDecimal 类型，并进行除法运算
                    val ecpm = ad?.ecpm?.toDouble() ?: 0.0
                    val result = BigDecimal(ecpm).divide(BigDecimal(1000), 20, RoundingMode.HALF_UP)
                    // 将结果转换为字符串表示形式
                    val formattedString: String = result.toPlainString()
                    showJson.addProperty("succeed", true)//广告加载是否成功
                    showJson.addProperty("adPlatform", "TradPlus")//广告平台
                    showJson.addProperty("countryCode", ad?.format ?: "")//国家代码
                    showJson.addProperty("adId", place)//广告Id
                    showJson.addProperty("platformResponseTime", "")//平台广告响应时间
                    showJson.addProperty("ecpm", formattedString)//广告单价
                    showJson.addProperty("dsp", ad?.adNetworkId ?: "")
                    showJson.addProperty("network", ad?.adNetworkId ?: "")
                    MyConfigUtil.initPostShowLog(showJson)

                    Log.d("ocean", "onAdShown decimalNumber->$formattedString")

                    Log.d("ocean", "onAdShown loadAdNumber->${loadAdNumber}")
                    Log.d("ocean", "onAdShown quantity.toInt()->${quantity.toInt()}")
                    if (loadAdNumber < quantity.toInt()) {//不能大于配置的数量
                        if (ecpmCool.isNotEmpty()) {
                            //满足配置的最高的价格则重新load这个被消耗的
                            Log.d("ocean", "onAdShown ecpmCool->${ecpmCool}")
                            Log.d("ocean", "onAdShown ecpmCool.toFloat()->${ecpmCool.toFloat()}")
                            if (formattedString.toFloat() >= ecpmCool.toFloat()) {
                                loadAd(place)
                            }
                        }
                    }

                    println("scanner_ad onAdShown")
                    aidlClient.sendAdsChange(packageName, getInsAdReturnCount(), 1, 0)
                    loadAndShowAdNumber--
                }

                override fun onAdClicked() {
                    aidlClient.sendBrushMiss()
                    Log.d("ocean", " 点击show广告")
                    aidlClient.sendAdsChange(packageName, getInsAdReturnCount(), 0, 1)
                }

                override fun onAdShowFailed(error: AdShowFailed?) {
                    aidlClient.sendBrushMiss()
                    Handler(Looper.getMainLooper()).post {
                        onAdShowFailedLiveData.value = true
                    }
                    Log.d("ocean", " show广告失败")
                    aidlClient.sendAdsChange(packageName, getInsAdReturnCount())
                    loadAndShowAdNumber--
                    showJson.addProperty("succeed", false)//广告加载是否成功
                    showJson.addProperty("adPlatform", "TradPlus")//广告平台
                    showJson.addProperty("adId", place)//广告Id
                    MyConfigUtil.initPostShowLog(showJson)
                }

                override fun onAdClosed() {
                    aidlClient.sendBrushMiss()
                    Handler(Looper.getMainLooper()).post {
                        onAdClosedLiveData.value = true
                    }
                    aidlClient.sendAdsChange(packageName, getInsAdReturnCount())
                }
            })
        }
    }

    //路径 /storage/emulated/0/phone.xml
    private fun getBidJson() {
        aidlClient.sendBrushMiss()
        Log.d("ocean-brush", "组装load数据与show数据上传，并且获取gaid")
        val linkId = UUID.randomUUID().toString().replace("-", "")
        GlobalScope.launch {
            withContext(Dispatchers.IO) {
                val gaId = AdvertisingIdClient.getAdvertisingIdInfo(this@MainActivity2).id
                Log.d("ocean", "getAdvertisingIdInfo gaId->${gaId}")

                viewJson.addProperty("设备ID", devicesID)
                viewJson.addProperty("货架号", shelfNumber)
//                viewJson.addProperty("IP获取时间", endIpTime - startIpTime)

                loadJson.addProperty("deviceId", devicesID)
                loadJson.addProperty("shelfNumber", shelfNumber)//货架号
                loadJson.addProperty("localIp", getLocalIpAddress())//本地IP
                loadJson.addProperty("linkId", linkId)//链路Id
                loadJson.addProperty("packageName", packageName)//包名
                loadJson.addProperty("gaid", gaId)
                loadJson.addProperty("dataId", dataId)
                loadJson.addProperty("carrierId",simId)
                loadJson.addProperty("getIpResponseTime", 0)
                loadJson.addProperty("packageVersion", 1)
                loadJson.addProperty("version", 3)
                loadJson.addProperty("phoneVersion", Build.MODEL)

                showJson.addProperty("deviceId", devicesID)
                showJson.addProperty("shelfNumber", shelfNumber)
                showJson.addProperty("localIp", getLocalIpAddress())//本地IP
                showJson.addProperty("linkId", linkId)//链路Id
                showJson.addProperty("packageName", packageName)//包名
                showJson.addProperty("gaid", gaId)
                showJson.addProperty("dataId", dataId)
                showJson.addProperty("carrierId",simId)
                showJson.addProperty("getIpResponseTime", 0)
                showJson.addProperty("version", 3)
                showJson.addProperty("phoneVersion", Build.MODEL)

                runOnUiThread {
                    binding.gaidTv.text = gaId
                    if (gaId != null) {
                        if (gaId == gaIdError) {
                            binding.gaidLayout.setBackgroundColor(getColor(R.color.red))
                            //gaID没有确的值就发送重置广播
                            appendLoadingTxt("没有获取到GAID，$timeLeft 秒后将会重置")
                            startCountdown()
                        } else {
                            binding.gaidLayout.setBackgroundColor(getColor(R.color.green))
                            initAd()
                        }
                    } else {
                        appendLoadingTxt("没有获取到GAID，$timeLeft 秒后将会重置")
                        startCountdown()
                    }
                }
            }
        }
    }

    /**
     * https://api.tikustok.com/app/common/getIPInfo
     * https://openapi.lux-ad.com/app/common/getIPInfo
     */
    private suspend fun getPublicIpAddress(): String = suspendCoroutine { continuation ->
        var publicIp = "0.0.0.0"
        try {
            VmHttpUtil.mInstance.getIPInfo(
                "https://openapi.lux-ad.com/app/common/getIPInfo",
                object : Callback {
                    override fun onFailure(call: Call, e: IOException) {
                        runOnUiThread {
                            appendLoadingTxt("获取IP失败")
                        }

                        continuation.resume(publicIp)
                    }

                    override fun onResponse(call: Call, response: Response) {
                        Log.d("ocean", "getIPInfo response->${response}")
                        if (response.code == 200) {
                            val responseData = response.body?.string()
                            if (responseData != null) {
                                val jsonObject = JSONObject(responseData)
                                Log.d("ocean", "getIPInfo jsonObject->${jsonObject}")
                                val status = jsonObject.optString("status")
                                if (status == "Success") {
                                    val data = jsonObject.getJSONObject("data")
                                    appendLoadingTxt("获取IP成功->${data}")
                                    Log.d("ocean", "getIPInfo data->${data}")
                                    publicIp = data.optString("ip")
                                    continuation.resume(publicIp)
                                } else {
                                    continuation.resume(publicIp)
                                }
                            } else {
                                continuation.resume(publicIp)
                            }
                        } else {
                            runOnUiThread {
                                appendLoadingTxt("获取IP失败->${response}")
                            }
                            continuation.resume(publicIp)
                        }
                    }
                })
        } catch (e: Exception) {
            e.printStackTrace()
            appendLoadingTxt("获取IP失败  catch->${e}")
            continuation.resume(publicIp)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        aidlClient.connectCompleteLiveData.removeObserver(connectCompleteObserver)
        aidlClient.paramCompleteLiveData.removeObserver(paramCompleteObserver)
        aidlClient.clickAdCompleteLiveData.removeObserver(clickAdCompleteObserver)
        onAdShownLiveData.removeObserver(onAdShownObserver)
        onAdShowFailedLiveData.removeObserver(onAdShowFailedObserver)
        onAdClosedLiveData.removeObserver(onAdCloseObserver)
        aidlClient.disconnect(this)
        stopCountdown()
        stopParamCountdown()
    }

    private fun getSimCountryIso(context: Activity): String {
        val telephonyManager = context.getSystemService("phone") as TelephonyManager?
        return telephonyManager?.simCountryIso?.uppercase(Locale.ENGLISH) ?: ""
    }

    private fun mnc(): String {
        val telephonyManager = getSystemService("phone") as TelephonyManager
        return try {
            val networkOperator = telephonyManager.networkOperator
            networkOperator.substring(3.coerceAtMost(networkOperator.length))
        } catch (e: Exception) {
            ""
        }
    }

    private fun mcc(): String {
        val telephonyManager = getSystemService("phone") as TelephonyManager
        return try {
            val networkOperator = telephonyManager.networkOperator
            networkOperator.substring(0, minOf(3, networkOperator.length))
        } catch (e: Exception) {
            ""
        }
    }

    @SuppressLint("Range")
    fun getDeviceIdFromProvider(callback: (String?, Boolean) -> Unit) {
        val uri = Uri.parse("content://com.guise.deviceidprovider/device_id")
        val cursor = contentResolver.query(uri, null, null, null, null)

        if (cursor != null && cursor.moveToFirst()) {
            val deviceId = cursor.getString(cursor.getColumnIndex("device_id"))
            cursor.close() // 关闭 Cursor
            callback(deviceId, true) // 成功读取到 Device ID
        } else {
            callback(null, false) // 读取失败
        }
    }

    /**
     * 通用进行重置，五秒倒计时
     */
    private var timeLeft = 5  // 倒计时时间
    private val countdownHandler = Handler(Looper.getMainLooper())
    private val countdownRunnable = object : Runnable {
        override fun run() {
            if (timeLeft > 0) {
                appendLoadingTxt("⏳ 剩余 $timeLeft 秒后执行 修改参数 指令")
                timeLeft--
                countdownHandler.postDelayed(this, 1000)  // 继续倒计时
            } else {
                appendLoadingTxt("🚀 执行 修改参数 指令")
                aidlClient.sendChangeParameters(packageName)
            }
        }
    }

    private fun startCountdown() {
        timeLeft = 5  // 重新初始化时间
        countdownHandler.post(countdownRunnable)  // 开始倒计时
    }

    private fun stopCountdown() {
        countdownHandler.removeCallbacks(countdownRunnable)  // 取消倒计时
    }

    /**
     * 参数修改失败，重新修改倒计时
     */
    private var paramTimeLeft = 15
    private val countdownParamHandler = Handler(Looper.getMainLooper())
    private val countdownParamRunnable = object : Runnable {
        override fun run() {
            if (paramTimeLeft > 0) {
                paramTimeLeft--
                countdownParamHandler.postDelayed(this, 1000)  // 继续倒计时
            } else {
                appendLoadingTxt("执行修改参数指令")
                aidlClient.sendChangeParameters(packageName)
            }
        }
    }

    private fun startParamCountdown() {
        paramTimeLeft = 15  // 重新初始化时间
        countdownParamHandler.post(countdownParamRunnable)  // 开始倒计时
    }

    private fun stopParamCountdown() {
        countdownParamHandler.removeCallbacks(countdownParamRunnable)  // 取消倒计时
    }
}
