package com.swiftcleaner.chovey.business.newAdmob

import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.applovin.mediation.MaxAd
import com.applovin.mediation.MaxAdListener
import com.applovin.mediation.MaxAdViewAdListener
import com.applovin.mediation.MaxError
import com.applovin.mediation.ads.MaxAdView
import com.applovin.mediation.ads.MaxAppOpenAd
import com.applovin.mediation.ads.MaxInterstitialAd
import com.applovin.mediation.nativeAds.MaxNativeAdListener
import com.applovin.mediation.nativeAds.MaxNativeAdLoader
import com.applovin.mediation.nativeAds.MaxNativeAdView
import com.applovin.sdk.AppLovinMediationProvider
import com.applovin.sdk.AppLovinSdk
import com.applovin.sdk.AppLovinSdkInitializationConfiguration
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.ads.mediation.admob.AdMobAdapter
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdLoader
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView
import com.google.android.gms.ads.FullScreenContentCallback
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.appopen.AppOpenAd
import com.google.android.gms.ads.interstitial.InterstitialAd
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
import com.google.android.gms.ads.nativead.NativeAd
import com.swiftcleaner.chovey.BuildConfig
import com.swiftcleaner.chovey.GlobalConfig
import com.swiftcleaner.chovey.GlobalConfig.ID_ADMOB_BANNER
import com.swiftcleaner.chovey.GlobalConfig.ID_ADMOB_INTER
import com.swiftcleaner.chovey.GlobalConfig.ID_ADMOB_NATIVE
import com.swiftcleaner.chovey.GlobalConfig.ID_ADMOB_OPEN
import com.swiftcleaner.chovey.GlobalConfig.ID_MAX_BANNER
import com.swiftcleaner.chovey.GlobalConfig.ID_MAX_INTER
import com.swiftcleaner.chovey.GlobalConfig.ID_MAX_NATIVE
import com.swiftcleaner.chovey.GlobalConfig.ID_MAX_OPEN
import com.swiftcleaner.chovey.GlobalConfig.KEY_MAX
import com.swiftcleaner.chovey.GlobalConfig.useAdmob
import com.swiftcleaner.chovey.R
import com.swiftcleaner.chovey.business.AdIntervalTimeUtils
import com.swiftcleaner.chovey.business.AdMaxCountUtils
import com.swiftcleaner.chovey.business.admob.ReportAdUtils
import com.swiftcleaner.chovey.business.newAdmob.AdDialog.showAdLoadingDialog
import com.swiftcleaner.chovey.databinding.LayoutAdNative1Binding
import com.swiftcleaner.chovey.databinding.LayoutAdNativeSmallBinding
import com.swiftcleaner.chovey.util.SPUtils
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.UUID
import java.util.concurrent.ConcurrentLinkedDeque

object AdmobHelps {


    private const val APP_OPEN_AD_UNIT = "openAd"
    private const val INTERSTITIAL_AD_UNIT = "interAd"
    private const val NATIVE_AD_UNIT = "nativeAd"
    private const val NO_AD = "no_ad"

    private const val KEY_AD_INTERVAL = "adInterval"
    private const val KEY_AD_REQUEST = "adRequest"
    private const val KEY_AD_CLICK = "adClick"
    private const val KEY_AD_SHOW = "adShow"

    private const val KEY_IS_SHOW_AD_BANNER = "isShowAdBanner"
    private const val KEY_IS_SHOW_AD_NATIVE = "isShowAdNative"
    private const val KEY_IS_SHOW_AD_EXIT_DIALOG_NATIVE = "isShowAdExitDialogNative"
    //    private const val KEY_IS_SHOW_AD_NATIVE_BOTTOM = "isShowAdNativeBottom"
    private const val KEY_IS_SHOW_AD_INTER = "isShowAdInter"
    private const val KEY_IS_SHOW_AD_BACK_INTER = "isShowAdBackInter"
    //    private const val KEY_IS_SHOW_AD_RESULT_BACK_INTER = "isShowAdResultBackInter"
    private const val KEY_IS_SHOW_GUIDE_AD = "isShowGuideAd"

    private const val DEFAULT_AD_INTERVAL = 0
    private const val DEFAULT_AD_REQUEST = 100
    private const val DEFAULT_AD_CLICK = 10
    private const val DEFAULT_AD_SHOW = 45

    private const val KEY_DISPLAY_NUMBER = "key_display_number"
    private const val KEY_REQUEST_NUMBER = "key_request_number"
    private const val KEY_CLICK_NUMBER = "key_click_number"
    private const val KEY_LAST_DISPLAY_TIME = "key_last_display_time"

    private const val EVENT_BLACKLIST = "blacklist"
    private const val EVENT_SHOW_DISPLAYS = "showDisPlays"
    private const val EVENT_SHOW_REQUESTS = "showRequests"
    private const val EVENT_SHOW_CLICKS = "showClicks"
    private const val EVENT_SHOW_INTERVAL_TIME = "showIntervalTime"

    //
    private val TAG = this::class.java.simpleName

    private var appOpenAd: AppOpenAd? = null
    private var appOpenMaxAd: MaxAppOpenAd? = null
    private var appOpenAdLoadTime: Long = 0
    private var isLoadingAppOpenAd = false

    private var interstitialAd: InterstitialAd? = null
    private var interstitialMaxAd: MaxInterstitialAd? = null
    private var interstitialAdLoadTime: Long = 0
    private var isLoadingInterstitialAd = false

    private var nativeAdLoadTime: Long = 0
    private var isLoadingNativeAd = false
    private val nativeCacheItems = ConcurrentLinkedDeque<NativeAd>()
    private var maxAdCacheItems = ConcurrentLinkedDeque<MaxAd>()
    private var maxNativeAdLoaderCacheItems = ConcurrentLinkedDeque<MaxNativeAdLoader>()

    private var lastShowTime: Long = 0

    private var showTime
        get() = SPUtils.getInstance().getLong(KEY_LAST_DISPLAY_TIME)
        set(value) = SPUtils.getInstance().putLong(KEY_LAST_DISPLAY_TIME, value)

    fun init(
        context: Context,
        loaded: (Int) -> Unit,
        failed: () -> Unit,
    ) {
        if (isBlacklist()) {
            failed.invoke()
            return
        }
        if (isAdmob()) {
            if (isAppOpenAdAvailable()) {
                loaded.invoke(0)
                return
            }
            if (openAdLoadFail() && isInterstitialAdAvailable()) {
                loaded.invoke(1)
                loadAppOpenAd(context)
                return
            }
            loadAppOpenAd(
                context,
                { loaded.invoke(0) },
                { if (openAdLoadFail()) loadInterstitialAd(context, { loaded.invoke(1) }, failed) else failed.invoke() }
            )
        } else {
            val initConfig = AppLovinSdkInitializationConfiguration.builder(
                KEY_MAX, context
            ).setMediationProvider(AppLovinMediationProvider.MAX).build()
            AppLovinSdk.getInstance(context).initialize(initConfig) {
                if (isAppOpenAdAvailable()) {
                    loaded.invoke(0)
                    return@initialize
                }
                if (openAdLoadFail() && isInterstitialAdAvailable()) {
                    loaded.invoke(1)
                    loadAppOpenAd(context)
                    return@initialize
                }
                loadAppOpenAd(context, { loaded.invoke(0) }, { failed.invoke() })
            }
        }
    }

    fun loadAppOpenAd(
        context: Context,
        loaded: (() -> Unit?)? = null,
        failed: (() -> Unit?)? = null,
    ) {
        if (!checkAvailable(APP_OPEN_AD_UNIT)) {
            failed?.invoke()
            return
        }
        if (isLoadingAppOpenAd) {
            failed?.invoke()
            return
        }
        isLoadingAppOpenAd = true
        Log.d(TAG, "app open Ad load.")
        val reqId = UUID.randomUUID().toString()
        ReportAdUtils.pullStartAd(
            reqId,
            APP_OPEN_AD_UNIT,
            (context as Activity).javaClass.simpleName
        )
        if (isAdmob()) {
            Log.d("isAdmob",isAdmob().toString())
            val adRequest = AdRequest.Builder().build()
            AppOpenAd.load(
                context,
                ID_ADMOB_OPEN,
                adRequest,
                object : AppOpenAd.AppOpenAdLoadCallback() {
                    override fun onAdFailedToLoad(loadAdError: LoadAdError) {
                        Log.d(TAG, "app open failed to load: ${loadAdError.message}")
                        isLoadingAppOpenAd = false
                        failed?.invoke()
                        ReportAdUtils.pullAd(
                            loadAdError.responseInfo,
                            APP_OPEN_AD_UNIT,
                            loadAdError.message,
                            reqId
                        )
                    }

                    override fun onAdLoaded(ad: AppOpenAd) {
                        Log.d(TAG, "app open Ad was loaded.")
                        appOpenAd = ad
                        appOpenAdLoadTime = System.currentTimeMillis()
                        isLoadingAppOpenAd = false
                        loaded?.invoke()
                        calculate(KEY_REQUEST_NUMBER)
                        ReportAdUtils.pullAd(ad.responseInfo, APP_OPEN_AD_UNIT, reqId = reqId)
                        ad.onPaidEventListener = ReportAdUtils.EventOnPaidEventListener(ad)
                    }
                })
        } else {
            Log.d("isAdmob",isAdmob().toString()+"1")
            appOpenMaxAd = MaxAppOpenAd(ID_MAX_OPEN, context)
            appOpenMaxAd?.setListener(object : MaxAdListener {
                override fun onAdLoaded(ad: MaxAd) {
                    Log.d(TAG, "app open Ad Max was loaded.")
                    appOpenAdLoadTime = System.currentTimeMillis()
                    loaded?.invoke()
                    calculate(KEY_REQUEST_NUMBER)
                    isLoadingAppOpenAd = false
                }

                override fun onAdDisplayed(p0: MaxAd) {
                }

                override fun onAdHidden(p0: MaxAd) {
                }

                override fun onAdClicked(p0: MaxAd) {
                }

                override fun onAdLoadFailed(p0: String, p1: MaxError) {
                    Log.d(TAG, "app open Max failed to load: $p0 ${p1.message}")
                    isLoadingAppOpenAd = false
                    failed?.invoke()
                }

                override fun onAdDisplayFailed(p0: MaxAd, p1: MaxError) {
                }

            })
            appOpenMaxAd?.loadAd()
        }
    }

    fun loadInterstitialAd(
        context: Context,
        loaded: (() -> Unit?)? = null,
        failed: (() -> Unit?)? = null,
    ) {
        if (!checkAvailable(INTERSTITIAL_AD_UNIT)) {
            failed?.invoke()
            return
        }
        if (isLoadingInterstitialAd) {
            failed?.invoke()
            return
        }
        isLoadingInterstitialAd = true
        Log.d(TAG, "interstitial Ad load.")
        val reqId = UUID.randomUUID().toString()
        ReportAdUtils.pullStartAd(
            reqId,
            INTERSTITIAL_AD_UNIT,
            (context as Activity).javaClass.simpleName
        )
        if (isAdmob()) {
            val adRequest = AdRequest.Builder().build()
            InterstitialAd.load(
                context,
                ID_ADMOB_INTER,
                adRequest,
                object : InterstitialAdLoadCallback() {
                    override fun onAdFailedToLoad(loadAdError: LoadAdError) {
                        Log.d(TAG, "interstitial Ad failed to load: ${loadAdError.message}")
                        interstitialAd = null
                        isLoadingInterstitialAd = false
                        failed?.invoke()
                        ReportAdUtils.pullAd(
                            loadAdError.responseInfo,
                            INTERSTITIAL_AD_UNIT,
                            loadAdError.message,
                            reqId
                        )
                    }

                    override fun onAdLoaded(ad: InterstitialAd) {
                        Log.d(TAG, "interstitial Ad was loaded.")
                        interstitialAd = ad
                        interstitialAdLoadTime = System.currentTimeMillis()
                        isLoadingInterstitialAd = false
                        loaded?.invoke()
                        calculate(KEY_REQUEST_NUMBER)
                        ReportAdUtils.pullAd(ad.responseInfo, INTERSTITIAL_AD_UNIT, reqId = reqId)
                        ad.onPaidEventListener = ReportAdUtils.EventOnPaidEventListener(ad)
                    }
                })
        } else {
            interstitialMaxAd = MaxInterstitialAd(ID_MAX_INTER, context)
            interstitialMaxAd?.setListener(object : MaxAdListener {
                override fun onAdLoaded(p0: MaxAd) {
                    Log.d(TAG, "interstitial Ad Max was loaded.")
                    interstitialAdLoadTime = System.currentTimeMillis()
                    isLoadingInterstitialAd = false
                    loaded?.invoke()
                    calculate(KEY_REQUEST_NUMBER)
                }

                override fun onAdDisplayed(p0: MaxAd) {
                }

                override fun onAdHidden(p0: MaxAd) {
                }

                override fun onAdClicked(p0: MaxAd) {
                }

                override fun onAdLoadFailed(p0: String, p1: MaxError) {
                    Log.d(TAG, "interstitial Ad failed to load: ${p1.message}")
                    interstitialMaxAd = null
                    isLoadingInterstitialAd = false
                    failed?.invoke()
                }

                override fun onAdDisplayFailed(p0: MaxAd, p1: MaxError) {
                }

            })
            interstitialMaxAd?.loadAd()
        }
    }

    fun loadNativeAd(activity: Activity, loaded: (() -> Unit?)? = null) {
        if (isBlacklist()) {
            return
        }

        Log.d(TAG, "native Ad load.")
        val reqId = UUID.randomUUID().toString()
        ReportAdUtils.pullStartAd(reqId, NATIVE_AD_UNIT, activity.javaClass.simpleName)
        if (isAdmob()) {
            val adLoader = AdLoader.Builder(
                activity,
                ID_ADMOB_NATIVE
            ).forNativeAd {
                Log.d(TAG, "native Ad loaded.")
                nativeAdLoadTime = System.currentTimeMillis()
                nativeCacheItems.offer(it)
                ReportAdUtils.pullAd(it.responseInfo, NATIVE_AD_UNIT, reqId = reqId)
                it.setOnPaidEventListener(ReportAdUtils.EventOnPaidEventListener(it))

                isLoadingNativeAd = false
                loaded?.invoke()
            }.withAdListener(object : AdListener() {
                override fun onAdLoaded() {
                    super.onAdLoaded()
                }

                override fun onAdClicked() {
                    Log.d(TAG, "native Ad clicked.")
                    ReportAdUtils.clickAd(
                        nativeCacheItems.lastOrNull()?.responseInfo,
                        NATIVE_AD_UNIT
                    )
                }

                override fun onAdFailedToLoad(loadAdError: LoadAdError) {
                    Log.d(TAG, "native Ad failed to load. ${loadAdError.message}")
                    ReportAdUtils.pullAd(
                        loadAdError.responseInfo,
                        NATIVE_AD_UNIT,
                        loadAdError.message,
                        reqId
                    )
                }
            }).build()
            adLoader.loadAd(AdRequest.Builder().build())
        } else {
            val nativeAdLoader = MaxNativeAdLoader(ID_MAX_NATIVE, activity)
            nativeAdLoader.setNativeAdListener(object : MaxNativeAdListener() {
                override fun onNativeAdLoaded(nativeAdView: MaxNativeAdView?, ad: MaxAd) {
                    Log.d(TAG, "native Ad Max loaded.")
                    nativeAdLoadTime = System.currentTimeMillis()
                    maxAdCacheItems.offer(ad)
                    maxNativeAdLoaderCacheItems.offer(nativeAdLoader)
                    loaded?.invoke()
                }

                override fun onNativeAdLoadFailed(adUnitId: String, error: MaxError) {
                    Log.d(TAG, "native Ad Max failed to load. ${error.message}")
                }

                override fun onNativeAdClicked(ad: MaxAd) {
                    Log.d(TAG, "native Ad Max clicked.")
                }
            })
            nativeAdLoader.loadAd()
        }
    }

    fun showAppOpenAd(
        activity: Activity,
        dismissed: (() -> Unit?)? = null,
        completed: (() -> Unit)? = null,
        failed: (() -> Unit?)? = null,
        isRetry: Boolean = false
    ) {
        if (activity.isFinishing || activity.isDestroyed) return
        if (!isShowAd()) {
            failed?.invoke()
            return
        }
        if (AdIntervalTimeUtils.isAdIntervalOpen() || AdMaxCountUtils.isOpenAdCountMax()){
            failed?.invoke()
            return
        }
        if (!checkAvailable(APP_OPEN_AD_UNIT, true)) {
            failed?.invoke()
            return
        }

        if (!isRetry) ReportAdUtils.showPrepareAd(APP_OPEN_AD_UNIT)
        if (!isAppOpenAdAvailable()) {
            Log.d(TAG, "The app open ad is not ready yet.")
            //ReportAdUtils.limitErrorAd(NO_AD, APP_OPEN_AD_UNIT)
            loadAppOpenAd(activity, {
                showAppOpenAd(activity, dismissed, completed, failed, true)
            }, {
                failed?.invoke()
            })
            return
        }

        if (isAdmob()) {
            appOpenAd?.fullScreenContentCallback = object : FullScreenContentCallback() {
                override fun onAdClicked() {
                    Log.d(TAG, "app open Ad was clicked")
                    calculate(KEY_CLICK_NUMBER)
                    ReportAdUtils.clickAd(appOpenAd?.responseInfo, APP_OPEN_AD_UNIT)
                }

                override fun onAdDismissedFullScreenContent() {
                    Log.d(TAG, "app open Ad dismissed fullscreen content.")
                    AdIntervalTimeUtils.updateOpenTime()
                    dismissed?.invoke()
                }

                override fun onAdFailedToShowFullScreenContent(adError: AdError) {
                    Log.d(TAG, "app open failed to show: ${adError.message}")
                    appOpenAd = null
                    failed?.invoke()
                    ReportAdUtils.showErrorAd(adError.message, APP_OPEN_AD_UNIT)
                    loadAppOpenAd(activity)
                }

                override fun onAdShowedFullScreenContent() {
                    Log.d(TAG, "app open Ad showed fullscreen content.")
                    lastShowTime = System.currentTimeMillis()
                    calculate(KEY_DISPLAY_NUMBER)
                    AdMaxCountUtils.addOpenAdCount()
                    completed?.invoke()
                    ReportAdUtils.showAd(appOpenAd?.responseInfo, APP_OPEN_AD_UNIT, activity)
                    appOpenAd = null
                    loadAppOpenAd(activity)
                }
            }
            appOpenAd?.show(activity)
        } else {
            appOpenMaxAd?.setListener(object : MaxAdListener {
                override fun onAdLoaded(ad: MaxAd) {

                }

                override fun onAdDisplayed(p0: MaxAd) {
                    Log.d(TAG, "app open Ad Max showed fullscreen content.")
                    appOpenMaxAd = null
                    calculate(KEY_DISPLAY_NUMBER)
                    AdMaxCountUtils.addOpenAdCount()
                    completed?.invoke()
                    loadAppOpenAd(activity)
                }

                override fun onAdHidden(p0: MaxAd) {
                    Log.d(TAG, "app open Ad Max dismissed fullscreen content.")
                    AdIntervalTimeUtils.updateOpenTime()
                    dismissed?.invoke()
                }

                override fun onAdClicked(p0: MaxAd) {
                    Log.d(TAG, "app open Ad Max was clicked")
                    calculate(KEY_CLICK_NUMBER)
                }

                override fun onAdLoadFailed(p0: String, p1: MaxError) {
                }

                override fun onAdDisplayFailed(p0: MaxAd, p1: MaxError) {
                    Log.d(TAG, "app open Max failed to show: ${p1.message}")
                    appOpenMaxAd = null
                    lastShowTime = System.currentTimeMillis()
                    failed?.invoke()
                    ReportAdUtils.showErrorAd(p1.message, APP_OPEN_AD_UNIT)
                    loadAppOpenAd(activity)
                }

            })
            appOpenMaxAd?.showAd()
        }
    }

    fun showInterstitialAd(
        activity: AppCompatActivity,
        dismissed: (() -> Unit)? = null,
        completed: (() -> Unit)? = null,
        failed: (() -> Unit)? = null,
        isRetry: Boolean = false,
        isShowInterAd: Boolean = isShowAdInter(),
        isShowDialogLading: Boolean = true
    ) {
        if (activity.isFinishing || activity.isDestroyed) return
        if (!isShowAd() || !isShowInterAd) {
            failed?.invoke()
            return
        }
        if (AdIntervalTimeUtils.isAdIntervalInterstitial() || AdMaxCountUtils.isInterAdCountMax()){
            failed?.invoke()
            return
        }

        if (!checkAvailable(INTERSTITIAL_AD_UNIT, true)) {
            failed?.invoke()
            return
        }

        if (!isRetry) ReportAdUtils.showPrepareAd(INTERSTITIAL_AD_UNIT)

        val dialog = if (isShowDialogLading) {
            activity.takeIf { !it.isFinishing && !it.isDestroyed }
                ?.showAdLoadingDialog(activity.getString(R.string.loading_ads_content))?.apply {
                    show()
                }
        } else null
        if (!isInterstitialAdAvailable()) {
            Log.d(TAG, "The interstitial ad is not ready yet.")
            //ReportAdUtils.limitErrorAd(NO_AD, INTERSTITIAL_AD_UNIT)
//            loadInterstitialAd(activity, {
//                showInterstitialAd(activity, dismissed, completed, failed, true)
//            }, {
//                failed?.invoke()
//            })
//            return
            loadInterstitialAd(
                activity,
                loaded = {
                    if (!checkAvailable(INTERSTITIAL_AD_UNIT, true)) {
                        dialog?.dismiss()
                        failed?.invoke()
                    } else {
//                        readyShow?.invoke()
                        activity.startCountdown(dialog) {
                            showInterAd(activity, dismissed, completed, failed)
                        }
                    }
                    print("loadInterstitialAd")
                },
                failed = {
                    dialog?.dismiss()
                    failed?.invoke()
                })
        } else {
//            readyShow?.invoke()
            activity.startCountdown(dialog) {
                showInterAd(activity, dismissed, completed, failed)
            }
        }
    }

    private fun showInterAd(
        activity: Activity,
        dismissed: (() -> Unit?)? = null,
        completed: (() -> Unit)? = null,
        failed: (() -> Unit?)? = null,
    ) {
        if (isAdmob()) {
            interstitialAd?.fullScreenContentCallback = object : FullScreenContentCallback() {
                override fun onAdClicked() {
                    Log.d(TAG, "interstitial Ad was clicked")
                    calculate(KEY_CLICK_NUMBER)
                    ReportAdUtils.clickAd(interstitialAd?.responseInfo, INTERSTITIAL_AD_UNIT)
                }

                override fun onAdDismissedFullScreenContent() {
                    Log.d(TAG, "interstitial Ad was dismissed.")
                    AdIntervalTimeUtils.updateInterstitialTime()
                    dismissed?.invoke()
                }

                override fun onAdFailedToShowFullScreenContent(adError: AdError) {
                    Log.d(TAG, "interstitial Ad failed to show: ${adError.message}")
                    interstitialAd = null
                    failed?.invoke()
                    ReportAdUtils.showErrorAd(adError.message, INTERSTITIAL_AD_UNIT)
                    loadInterstitialAd(activity)
                }

                override fun onAdShowedFullScreenContent() {
                    Log.d(TAG, "interstitial Ad showed fullscreen content.")
                    lastShowTime = System.currentTimeMillis()
                    AdMaxCountUtils.addInterAdCount()
                    completed?.invoke()
                    calculate(KEY_DISPLAY_NUMBER)
                    ReportAdUtils.showAd(
                        interstitialAd?.responseInfo,
                        INTERSTITIAL_AD_UNIT,
                        activity
                    )
                    interstitialAd = null
                    loadInterstitialAd(activity)
                }
            }
            interstitialAd?.show(activity)
        } else {
            interstitialMaxAd?.setListener(object : MaxAdListener {
                override fun onAdLoaded(p0: MaxAd) {

                }

                override fun onAdDisplayed(p0: MaxAd) {
                    Log.d(TAG, "interstitial Ad Max showed fullscreen content.")
                    interstitialMaxAd = null
                    lastShowTime = System.currentTimeMillis()
                    AdMaxCountUtils.addInterAdCount()
                    completed?.invoke()
                    calculate(KEY_DISPLAY_NUMBER)
                    loadInterstitialAd(activity)
                }

                override fun onAdHidden(p0: MaxAd) {
                    Log.d(TAG, "interstitial Ad Max was dismissed.")
                    AdIntervalTimeUtils.updateInterstitialTime()
                    dismissed?.invoke()
                }

                override fun onAdClicked(p0: MaxAd) {
                    Log.d(TAG, "interstitial Ad Max was clicked")
                    calculate(KEY_CLICK_NUMBER)
                }

                override fun onAdLoadFailed(p0: String, p1: MaxError) {

                }

                override fun onAdDisplayFailed(p0: MaxAd, p1: MaxError) {
                    Log.d(TAG, "interstitial Ad MaX failed to show: ${p1.message}")
                    interstitialMaxAd = null
                    failed?.invoke()
                    ReportAdUtils.showErrorAd(p1.message, INTERSTITIAL_AD_UNIT)
                    loadInterstitialAd(activity)
                }

            })
            interstitialMaxAd?.showAd(activity)
        }
    }

    fun showBackNativeAd(
        activity: Activity,
        parent: ViewGroup,
        layout: Int = R.layout.layout_ad_native1,
        isRetry: Boolean = false,
    ) {
        showNativeAd(activity, parent, layout, isShowAdExitDialogNative(), isRetry)
    }

    fun showLoadingNativeAd(
        activity: Activity,
        parent: ViewGroup,
        layout: Int = R.layout.layout_ad_native1,
        isRetry: Boolean = false,
    ) {
        showNativeAd(activity, parent, layout, isShowLoadingNative(), isRetry)
    }

    fun showNativeAd(
        activity: Activity,
        parent: ViewGroup,
        layout: Int = R.layout.layout_ad_native1,
        isShowAdNative: Boolean = isShowAdNative(),
        isRetry: Boolean = false,
    ) {
        if (activity.isFinishing || activity.isDestroyed) return
        if (!isShowAd()) {
            parent.isGone = true
            return
        }
        if (AdIntervalTimeUtils.isAdIntervalNative() || AdMaxCountUtils.isOpenAdCountMax()){
            parent.isGone = true
            return
        }
        if (!isShowAdNative || isBlacklist()) {
            parent.isGone = true
            return
        }
        initShimmerFrameLayout(activity, parent, layout)
        val layoutName = activity.resources.getResourceEntryName(layout)
        Log.d("layout111", "Layout name: $layoutName")


        if (!isRetry) ReportAdUtils.showPrepareAd(NATIVE_AD_UNIT)
        if (isAdmob()) {
            val nativeAd = getNativeAd()
            if (nativeAd == null) {
                Log.d(TAG, "The native ad is not ready yet.")
                //ReportAdUtils.limitErrorAd(NO_AD, NATIVE_AD_UNIT)
                loadNativeAd(activity) {
                    showNativeAd(
                        activity,
                        parent,
                        layout,
                        isShowAdNative,
                        true
                    )
                }
                return
            }
            NativeView1(parent.context, layout).run {
                parent.removeAllViews()
                setNativeAd(nativeAd)
                parent.addView(this)
                parent.isVisible = true
                ReportAdUtils.showAd(nativeAd.responseInfo, NATIVE_AD_UNIT, activity)
            }
            AdIntervalTimeUtils.updateNativeTime()
            AdMaxCountUtils.addNativeAdCount()
            loadNativeAd(activity)
        } else {
            val max = getMaxAd()
            if (max == null) {
                Log.d(TAG, "The native Ad Max is not ready yet.")
                if (isRetry) return
                loadNativeAd(activity) {
                    showNativeAd(
                        activity,
                        parent,
                        layout,
                        isShowAdNative,
                        true
                    )
                }
                return
            }
            NativeView1(parent.context, layout).run {
                parent.removeAllViews()
                setNativeAd(max.second, max.first)
                parent.addView(this)
                parent.isVisible = true
            }
            AdIntervalTimeUtils.updateNativeTime()
            AdMaxCountUtils.addNativeAdCount()
            if (maxAdCacheItems.size == 0)
                loadNativeAd(activity)
        }
    }

    private fun initShimmerFrameLayout(
        activity: Activity,
        parent: ViewGroup,
        layout: Int,
    ) {
        val shimmerFrameLayout = activity.layoutInflater.inflate(
            R.layout.shimmer_layout,
            parent,
            false
        ) as ShimmerFrameLayout
        parent.addView(shimmerFrameLayout)

        // 根据不同的布局文件设置占位动画的内容
        if (layout == R.layout.layout_ad_native1) {
            val binding =
                LayoutAdNative1Binding.inflate(activity.layoutInflater, shimmerFrameLayout, false)
            shimmerFrameLayout.addView(binding.root)
//            binding.secondContainer.isInvisible = true
//            binding.bgContainer.background = null
        }
        if (layout == R.layout.layout_ad_native_small) {
            val binding = LayoutAdNativeSmallBinding.inflate(
                activity.layoutInflater,
                shimmerFrameLayout,
                false
            )
            shimmerFrameLayout.addView(binding.root)
            binding.adCallToAction.isInvisible = true
//            binding.bgContainer.background = null
        }

        // 设置背景颜色并启动动画
        shimmerFrameLayout.setBackgroundColor(activity.getColor(R.color.bg_ad))
        shimmerFrameLayout.startShimmer()
    }

    private fun getMaxAd(): Pair<MaxAd, MaxNativeAdLoader>? {
        val maxAd = maxAdCacheItems.poll()
        val maxNativeAdLoader = maxNativeAdLoaderCacheItems.poll()
        if (maxAd == null || maxNativeAdLoader == null) return null
        if (!isNativeAdAvailable()) {
            return getMaxAd()
        }
        return Pair(maxAd, maxNativeAdLoader)
    }

    private fun getNativeAd(): NativeAd? {
        val nativeAd = nativeCacheItems.poll() ?: return null
        if (!wasLoadTimeLessThanNHoursAgo(1, nativeAdLoadTime)) {
            return getNativeAd()
        }
        return nativeAd
    }

    fun showBannerAd(
        context: Context,
        adViewContainer: ViewGroup,
        collapsible: String? = "bottom",
        completed: (() -> Unit?)? = null,
        failed: (() -> Unit?)? = null
    ) {
//        if (!isAdmob()) return

        adViewContainer.viewTreeObserver.addOnGlobalLayoutListener(object :
            ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {

                val screenPixelDensity = context.resources.displayMetrics.density
                val adWidth = (adViewContainer.width / screenPixelDensity).toInt()
                val adSize =
                    AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(context, adWidth)
                showBannerAd(context, adViewContainer, adSize, collapsible, completed, failed)

                adViewContainer.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        })
    }

    fun showBannerAd(
        context: Context,
        adViewContainer: ViewGroup,
        adSize: AdSize,
        collapsible: String? = "bottom",
        completed: (() -> Unit?)? = null,
        failed: (() -> Unit?)? = null
    ) {
        if (!isShowAdBanner() || isBlacklist()) {
            adViewContainer.isGone = true
            failed?.invoke()
            return
        }

        Log.d(TAG, "banner Ad load.")
        val adView = AdView(context)
        adView.adUnitId = ID_ADMOB_BANNER
        adView.setAdSize(adSize)
        val extras = Bundle()
        if (collapsible != "bottom") {
            extras.putString("collapsible", collapsible)
        }
        val adRequest = AdRequest.Builder()
            .addNetworkExtrasBundle(AdMobAdapter::class.java, extras)
            .build()
        adView.loadAd(adRequest)
        adView.adListener = object : AdListener() {
            override fun onAdClicked() {
                Log.d(TAG, "banner Ad clicked.")
            }

            override fun onAdFailedToLoad(loadAdError: LoadAdError) {
                Log.d(TAG, "banner Ad failed to load: ${loadAdError.message}")
                failed?.invoke()
            }

            override fun onAdLoaded() {
                Log.d(TAG, "banner Ad loaded.")
                completed?.invoke()
                adViewContainer.removeAllViews()
                adViewContainer.addView(adView)
            }
        }

    }

    private fun showBannerAd(
        context: Context,
        adViewContainer: ViewGroup,
        completed: (() -> Unit?)? = null,
        failed: (() -> Unit?)? = null,
    ) {
        if (!isShowAdBanner() || isBlacklist()) {
            failed?.invoke()
            return
        }

        Log.d(TAG, "banner Ad Max load.")
        val adView = MaxAdView(ID_MAX_BANNER, context)
        adView.setListener(object : MaxAdViewAdListener {
            override fun onAdLoaded(p0: MaxAd) {
                Log.d(TAG, "banner Ad Max loaded.")
                completed?.invoke()
            }

            override fun onAdDisplayed(p0: MaxAd) {
            }

            override fun onAdHidden(p0: MaxAd) {

            }

            override fun onAdClicked(p0: MaxAd) {
                Log.d(TAG, "banner Ad Max clicked.")
            }

            override fun onAdLoadFailed(p0: String, p1: MaxError) {
                Log.d(TAG, "banner Ad Max failed to load: ${p1.message}")
                failed?.invoke()
            }

            override fun onAdDisplayFailed(p0: MaxAd, p1: MaxError) {

            }

            override fun onAdExpanded(p0: MaxAd) {

            }

            override fun onAdCollapsed(p0: MaxAd) {

            }

        })
        adViewContainer.removeAllViews()
        adViewContainer.addView(adView)
        adView.loadAd()

    }

    fun isShowAd(): Boolean {
        val isShowAd = SPUtils.getInstance().getInt("isShowAd")
        return isShowAd == 1
    }

    fun isShowAdBanner(): Boolean {
        val isShowAdBanner = SPUtils.getInstance().getInt(KEY_IS_SHOW_AD_BANNER)
        return isShowAdBanner == 1 && isShowAd()
    }

    fun isShowAdNative(): Boolean {
        val isShowAdNative = SPUtils.getInstance().getInt(KEY_IS_SHOW_AD_NATIVE)
        return isShowAdNative == 1 && isShowAd()
    }

    fun isShowAdExitDialogNative(): Boolean {
        val isShowAdNative = SPUtils.getInstance().getInt(KEY_IS_SHOW_AD_EXIT_DIALOG_NATIVE)
        return isShowAdNative == 1 && isShowAd()
    }

//    fun isShowAdNativeBottom(): Boolean {
//        val isShowAdNative = SPUtils.getInstance().getInt(KEY_IS_SHOW_AD_NATIVE_BOTTOM)
//        return isShowAdNative == 1 && isShowAd()
//    }

    fun isShowAdInter(): Boolean {
        val isShowAdInter = SPUtils.getInstance().getInt(KEY_IS_SHOW_AD_INTER)
        return isShowAdInter == 1 && isShowAd()
    }

    fun isShowAdBackInter(): Boolean {
        val isShowAdBackInter = SPUtils.getInstance().getInt(KEY_IS_SHOW_AD_BACK_INTER)
        return isShowAdBackInter == 1 && isShowAd()
    }

//    fun isShowAdResultBackInter(): Boolean {
//        val isShowAdBackInter = SPUtils.getInstance().getInt(KEY_IS_SHOW_AD_RESULT_BACK_INTER)
//        return isShowAdBackInter == 1 && isShowAd()
//    }

    fun isShowGuideAd(): Boolean {
        val isShowGuideAd = SPUtils.getInstance().getInt(KEY_IS_SHOW_GUIDE_AD)
        return isShowGuideAd == 1 && isShowAd()
    }

    fun isShowLoadingNative(): Boolean {
        val isShowLoadingNative = SPUtils.getInstance().getInt("isShowLoadingNative")
        return isShowLoadingNative == 1 && isShowAd()
    }

    // 清理相关按钮的插屏
    fun isDeleteInterAd(): Boolean {
        val isDeleteInterAd = SPUtils.getInstance().getInt("isDeleteInterAd")
        return isDeleteInterAd == 1 && isShowAd()
    }

    fun openAdLoadFail(): Boolean {
        val openAdloadfail = SPUtils.getInstance().getInt("openAdloadfail", 1)
        return openAdloadfail == 1
    }

    fun apiSwitch(): Boolean {
        val apiSwitch = SPUtils.getInstance().getInt("api_switch", 1)
        return apiSwitch == 1
    }

    fun isAppOpenAdAvailable(): Boolean {
        return (if (isAdmob()) appOpenAd != null else appOpenMaxAd?.isReady == true) && wasLoadTimeLessThanNHoursAgo(
            1,
            appOpenAdLoadTime
        )
    }

    fun isInterstitialAdAvailable(): Boolean {
        return (if (isAdmob()) interstitialAd != null else interstitialMaxAd?.isReady == true) && wasLoadTimeLessThanNHoursAgo(
            1,
            interstitialAdLoadTime
        )
    }

    fun isNativeAdAvailable(): Boolean {
        return wasLoadTimeLessThanNHoursAgo(1, nativeAdLoadTime)
    }

    private fun wasLoadTimeLessThanNHoursAgo(numHours: Long, time: Long): Boolean {
        val dateDifference: Long = System.currentTimeMillis() - time
        val numMilliSecondsPerHour: Long = 3600000
        return dateDifference < numMilliSecondsPerHour * numHours
    }

    private fun isBlacklist(): Boolean {
        return if (BuildConfig.DEBUG) false else GlobalConfig.blacklist != 1
    }

    //    private fun isBlacklist(): Boolean {
//        return false
//    }
    private fun isAdmob(): Boolean {
        return useAdmob == 1
    }
    //    private fun isAdmob(): Boolean {
//        return false
//    }
    private fun checkAvailable(adUnit: String, checkIntervalTime: Boolean = false): Boolean {
        if (isBlacklist()) {
            ReportAdUtils.limitErrorAd(EVENT_BLACKLIST, adUnit)
            return false
        }
        reset()
        val displayNumber = SPUtils.getInstance().getInt(KEY_DISPLAY_NUMBER)
        val requestNumber = SPUtils.getInstance().getInt(KEY_REQUEST_NUMBER)
        val clickNumber = SPUtils.getInstance().getInt(KEY_CLICK_NUMBER)
        val adShow = SPUtils.getInstance().getInt(KEY_AD_SHOW, DEFAULT_AD_SHOW)
        val adRequest = SPUtils.getInstance().getInt(KEY_AD_REQUEST, DEFAULT_AD_REQUEST)
        val adClick = SPUtils.getInstance().getInt(KEY_AD_CLICK, DEFAULT_AD_CLICK)
        if (displayNumber >= adShow) {
            ReportAdUtils.limitErrorAd(EVENT_SHOW_DISPLAYS, adUnit)
            return false
        }
        if (requestNumber >= adRequest) {
            ReportAdUtils.limitErrorAd(EVENT_SHOW_REQUESTS, adUnit)
            return false
        }
        if (clickNumber >= adClick) {
            ReportAdUtils.limitErrorAd(EVENT_SHOW_CLICKS, adUnit)
            return false
        }
        if (!checkIntervalTime) return true

        val interval =
            SPUtils.getInstance().getInt(KEY_AD_INTERVAL, DEFAULT_AD_INTERVAL) * 60 * 1000
        val flag = System.currentTimeMillis() - lastShowTime > interval
        if (!flag) {
            ReportAdUtils.limitErrorAd(EVENT_SHOW_INTERVAL_TIME, adUnit)
        }
        return flag
    }

    fun Long.toFormatTime4(): String {
        return SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).format(this)
    }

    fun areTimestampsSameDay(timestamp1: Long, timestamp2: Long): Boolean {
        val calendar1 = Calendar.getInstance().apply { timeInMillis = timestamp1 }
        val calendar2 = Calendar.getInstance().apply { timeInMillis = timestamp2 }

        // 比较年、月、日是否相同
        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR) &&
                calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH) &&
                calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH)
    }

    fun calculate(key: String) {
        reset()
        val value = SPUtils.getInstance().getInt(key)
        SPUtils.getInstance().putInt(key, value + 1)
    }

    private fun reset() {
        val currentTime = System.currentTimeMillis()
        if (showTime.toInt() == 0 || showTime.toFormatTime4() != currentTime.toFormatTime4()) {
            showTime = currentTime
            SPUtils.getInstance().putInt(KEY_DISPLAY_NUMBER, 0)
            SPUtils.getInstance().putInt(KEY_REQUEST_NUMBER, 0)
            SPUtils.getInstance().putInt(KEY_CLICK_NUMBER, 0)
        }
    }

    @SuppressLint("SetTextI18n")
    private fun AppCompatActivity.startCountdown(dialog: Dialog?, onComplete: () -> Unit) {
        lifecycleScope.launch {
            val loadingText = dialog?.findViewById<TextView>(R.id.tv_loading)
            val orgText = loadingText?.text ?: ""
            if (dialog != null && !dialog.isShowing) dialog.show()
            (3 downTo 0).forEach { time ->
                loadingText?.text = "$orgText($time)"
                delay(1000)
            }
            onComplete()
            dialog?.dismiss()
        }
    }
}