package com.base.scanqrclear.luma

import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.ViewGroup
import android.view.ViewTreeObserver
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.base.scanqrclear.GlobalConfig.ID_ADMOB_BANNER
import com.base.scanqrclear.GlobalConfig.ID_ADMOB_INTER
import com.base.scanqrclear.GlobalConfig.ID_ADMOB_NATIVE
import com.base.scanqrclear.GlobalConfig.ID_ADMOB_OPEN
import com.base.scanqrclear.GlobalConfig.ID_MAX_BANNER
import com.base.scanqrclear.GlobalConfig.ID_MAX_INTER
import com.base.scanqrclear.GlobalConfig.ID_MAX_NATIVE
import com.base.scanqrclear.GlobalConfig.ID_MAX_OPEN
import com.base.scanqrclear.GlobalConfig.KEY_MAX
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.google.android.gms.ads.nativead.NativeAdOptions
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.UUID

object AdmobHelps {

    //
    const val KEY_INIT = "key_init"
    const val KEY_AD = "sAd"
    const val KEY_BLACKLIST = "blacklist"
    const val KEY_REFERRER = "referrer"
    const val KEY_UUID = "key_uuid"
    const val KEY_GOOGLE_ADVERTISER_ID = "key_google_advertiser_id"
    const val KEY_DEVICE_NAME = "key_device_name"
    const val KEY_INSTALL_TIME = "key_install_time"
    const val KEY_CLEAN_LAST_TIME = "key_clean_last_time"
    const val KEY_CLEANUP_SIZE = "key_cleanup_size"
    const val KEY_NOT_CLEAN_TIME = "key_not_clean_time"
    const val KEY_NOTIFICATION_ID = "key_notification_id"
    const val KEY_APP_BACKGROUND = "key_app_background"
    const val KEY_HOME_COUNT = "key_home_count"
    const val KEY_DEVICE_SCAN = "key_device_scan"
    const val KEY_SCORE = "key_score"

    const val ID_CLEAN_JUNK = 31000
    const val ID_WHATSAPP = 31010
    const val ID_BATTERY_INFO = 31020
    const val ID_LARGE_FILE_CLEANER = 31030
    const val ID_PHOTO_COMPRESSION = 31040
    const val ID_SCREENSHOT_CLEAN = 31050
    const val ID_APP_INSTALL = 31060
    const val ID_APP_UNINSTALL = 31070
    const val ID_NOT_CLEANED = 31080
    const val ID_BATTERY_LEVEL = 31090
    const val ID_APP_MANAGER = 31100
    const val ID_HOME = 31200


    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_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 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 const val TAG = "AdmobHelps"

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

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

    var isLoadingAppOpenAd = false
    var isLoadingInterstitialAd = false

    private var lastShowTime: Long = 0

    var blacklist = 1

    private var showTime
        get() = SpUtils.getInstance()
            .getLong(KEY_LAST_DISPLAY_TIME, System.currentTimeMillis())
        set(value) = SpUtils.getInstance().putLong(KEY_LAST_DISPLAY_TIME, value)

    inline var useAdmob
        get() = SpUtils.getInstance().getBoolean("sAd", true)
        set(value) = SpUtils.getInstance().putBoolean("sAd", value)

    fun init(
        context: Context,
        loaded: (Int) -> Unit,
        failed: () -> Unit,
    ) {
        if (isBlacklist()) {
            failed.invoke()
            return
        }
        if (useAdmob) {
            if (isAppOpenAdAvailable()) {
                loaded.invoke(0)
                return
            }
            if (isInterstitialAdAvailable()) {
                loaded.invoke(1)
                loadAppOpenAd(context)
                return
            }
            loadAppOpenAd(context, { loaded.invoke(0) }, { 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 (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 (useAdmob) {
            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 {
            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 (useAdmob) {
            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 showAppOpenAd(
        activity: Activity,
        dismissed: (() -> Unit?)? = null,
        completed: (() -> Unit)? = null,
        failed: (() -> Unit?)? = null,
        isRetry: Boolean = false
    ) {
        if (activity.isFinishing || activity.isDestroyed) 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 (useAdmob) {
            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.")
                    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)
                    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)
                    completed?.invoke()
                    loadAppOpenAd(activity)
                }

                override fun onAdHidden(p0: MaxAd) {
                    Log.d(TAG, "app open Ad Max dismissed fullscreen content.")
                    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: Activity,
        dismissed: (() -> Unit?)? = null,
        completed: (() -> Unit)? = null,
        failed: (() -> Unit?)? = null,
        isRetry: Boolean = false
    ) {
        if (activity.isFinishing || activity.isDestroyed) return

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

        if (!isRetry) ReportAdUtils.showPrepareAd(INTERSTITIAL_AD_UNIT)
        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
        }

        if (useAdmob) {
            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.")
                    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()
                    calculate(KEY_DISPLAY_NUMBER)
                    completed?.invoke()
                    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.")
                    calculate(KEY_DISPLAY_NUMBER)
                    completed?.invoke()
                    interstitialMaxAd = null
                    loadInterstitialAd(activity)
                }

                override fun onAdHidden(p0: MaxAd) {
                    Log.d(TAG, "interstitial Ad Max was dismissed.")
                    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
                    lastShowTime = System.currentTimeMillis()
                    failed?.invoke()
                    ReportAdUtils.showErrorAd(p1.message, INTERSTITIAL_AD_UNIT)
                    loadInterstitialAd(activity)
                }

            })
            interstitialMaxAd?.showAd(activity)
        }
    }

    fun showNativeAd(
        activity: Activity,
        completed: ((nativeAd: NativeAd) -> Unit)? = null,
        maxCompleted: ((nativeAdLoader: MaxNativeAdLoader, nativeMaxAd: MaxAd) -> Unit)? = null,
        failed: (() -> Unit?)? = null
    ) {
        if (!isShowAdNative() || isBlacklist()) {
            failed?.invoke()
            return
        }

        Log.d(TAG, "native Ad load.")
        ReportAdUtils.showPrepareAd(NATIVE_AD_UNIT)
        if (useAdmob) {
            var nativeAd: NativeAd? = null
            val adLoader = AdLoader.Builder(activity, ID_ADMOB_NATIVE)
                .forNativeAd { ad: NativeAd ->
                    completed?.invoke(ad)
                    ReportAdUtils.showAd(ad.responseInfo, NATIVE_AD_UNIT, activity)
                    ad.setOnPaidEventListener(ReportAdUtils.EventOnPaidEventListener(ad))
                    nativeAd = ad
                }
                .withAdListener(object : AdListener() {
                    override fun onAdClicked() {
                        Log.d(TAG, "native Ad clicked.")
                        ReportAdUtils.clickAd(nativeAd?.responseInfo, NATIVE_AD_UNIT)
                    }

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

                    override fun onAdLoaded() {
                        Log.d(TAG, "native Ad loaded.")
                    }
                })
                .withNativeAdOptions(NativeAdOptions.Builder().build())
                .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.")
                    maxCompleted?.invoke(nativeAdLoader, ad)
                }

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

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

    fun showBannerAd(
        context: Context,
        adViewContainer: ViewGroup,
        collapsible: String? = "bottom",
        completed: (() -> Unit?)? = null,
        failed: (() -> Unit?)? = null
    ) {
        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()) {
            failed?.invoke()
            return
        }

        Log.d(TAG, "banner Ad load.")
        val adView = AdView(context)
        adView.adUnitId = ID_ADMOB_BANNER
        adView.setAdSize(adSize)
        val extras = Bundle()
        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 isShowAdBanner(): Boolean {
        val isShowAdBanner = SpUtils.getInstance().getInt(KEY_IS_SHOW_AD_BANNER)
        return isShowAdBanner == 1
    }

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

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

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

    fun isShowAdResultBackInter(): Boolean {
        val isShowAdInter = SpUtils.getInstance().getInt(KEY_IS_SHOW_AD_RESULT_BACK_INTER)
        return isShowAdInter == 1
    }

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

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

    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 blacklist != 1
    }

    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)
        }
    }
}