package com.remax.bill.ads

import android.app.Activity
import android.content.Context
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdValue
import com.google.android.gms.ads.FullScreenContentCallback
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.OnPaidEventListener
import com.google.android.gms.ads.OnUserEarnedRewardListener
import com.google.android.gms.ads.rewarded.RewardItem
import com.google.android.gms.ads.rewarded.RewardedAd
import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback
import com.remax.bill.BuildConfig
import com.remax.bill.ads.config.AdConfigManager
import com.remax.bill.ads.interceptor.ClickLimitInterceptor
import com.remax.bill.ads.interceptor.GlobalAdSwitchInterceptor
import com.remax.bill.ads.interceptor.InterceptorChain
import com.remax.bill.ads.interceptor.ShowCountLimitInterceptor
import com.remax.bill.ads.interceptor.ShowIntervalLimitInterceptor
import com.remax.base.ads.AdRevenueData
import com.remax.base.ads.AdRevenueManager
import com.remax.base.ads.RevenueInfo
import com.remax.base.ext.KvIntDelegate
import com.remax.base.report.DataReportManager
import com.remax.bill.ads.ext.CommonRewardedData
import com.remax.bill.ads.log.AdLogger
import com.remax.bill.ads.util.PositionGet
import com.remax.bill.ui.dialog.ADLoadingDialog
import kotlin.math.ceil
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.also
import kotlin.collections.count
import kotlin.collections.firstOrNull
import kotlin.collections.indexOfFirst
import kotlin.coroutines.resume
import kotlin.let
import kotlin.text.orEmpty
import kotlin.to

/**
 * 激励广告控制器
 */
class RewardedAdController private constructor() {

    // 累积点击统计（持久化）
    private var totalClickCount by KvIntDelegate("rewarded_ad_total_clicks", 0)

    // 累积关闭统计（持久化）
    private var totalCloseCount by KvIntDelegate("rewarded_ad_total_close", 0)

    // 累积加载次数统计（持久化）
    private var totalLoadCount by KvIntDelegate("rewarded_ad_total_loads", 0)

    // 累积加载成功次数统计（持久化）
    private var totalLoadSucCount by KvIntDelegate("rewarded_ad_total_load_suc", 0)

    // 累积展示失败次数统计（持久化）
    private var totalShowFailCount by KvIntDelegate("rewarded_ad_total_show_fails", 0)

    // 累积触发统计（持久化）
    private var totalShowTriggerCount by KvIntDelegate("rewarded_ad_total_show_triggers", 0)

    // 累积展示统计（持久化）
    private var totalShowCount by KvIntDelegate("rewarded_ad_total_shows", 0)

    // 累积奖励获得次数统计（持久化）
    private var totalRewardEarnedCount by KvIntDelegate("rewarded_ad_total_reward_earned", 0)

    // 当前广告的收益信息（临时存储）
    private var currentAdValue: AdValue? = null

    // 激励广告是否正在显示的标识
    private var isShowing: Boolean = false

    companion object {
        private const val DEFAULT_CACHE_SIZE_PER_AD_UNIT = 1

        @Volatile
        private var INSTANCE: RewardedAdController? = null

        fun getInstance(): RewardedAdController {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: RewardedAdController().also { INSTANCE = it }
            }
        }
    }

    // 内存缓存池 - 存储预加载的广告
    private val adCachePool = mutableListOf<CachedRewardedAd>()
    private val maxCacheSizePerAdUnit = DEFAULT_CACHE_SIZE_PER_AD_UNIT

    // 拦截器链
    private val interceptorChain = InterceptorChain(
        interceptors = listOf(
            GlobalAdSwitchInterceptor(),
            ShowCountLimitInterceptor(),
            ShowIntervalLimitInterceptor(),
            ClickLimitInterceptor()
        )
    )

    /**
     * 缓存的激励广告数据类
     */
    private data class CachedRewardedAd(
        val ad: RewardedAd,
        val adUnitId: String,
        val loadTime: Long = System.currentTimeMillis()
    ) {
        fun isExpired(): Boolean {
            return System.currentTimeMillis() - loadTime > 1 * 60 * 60 * 1000L
        }
    }

    /**
     * 预加载广告
     */
    suspend fun preloadAd(context: Context, adUnitId: String? = null): AdResult<Unit> {
        if(!GlobalAdSwitchInterceptor.isGlobalAdEnabled()){
            return AdResult.Failure(
                AdException(
                    code = -100,
                    message = "全局广告已关闭，中断加载"
                ))
        }
        val finalAdUnitId = adUnitId ?: BuildConfig.ADMOB_REWARDED_ID
        return loadAdToCache(context, finalAdUnitId)
    }

    /**
     * 显示广告
     */
    suspend fun showAd(
        activity: Activity,
        adUnitId: String? = null,
        onRewardEarned: ((RewardItem, CommonRewardedData) -> Unit)? = null,
        closeCallback: () -> Unit
    ): AdResult<Unit> {
        val finalAdUnitId = adUnitId ?: BuildConfig.ADMOB_REWARDED_ID

        // 累积触发统计
        totalShowTriggerCount++
        AdLogger.d("Admob激励广告累积触发展示次数: $totalShowTriggerCount")

        reportAdData(
            eventName = "ad_position",
            params = mapOf(
                "ad_unit_name" to finalAdUnitId,
                "position" to PositionGet.get(),
                "number" to totalShowTriggerCount
            )
        )

        // 拦截器检查
//        when (val interceptResult = interceptorChain.intercept(activity, AdConfigManager.getRewardedConfig())) {
//            is AdResult.Failure -> {
//                // 累积展示失败次数统计
//                totalShowFailCount++
//                AdLogger.d("激励广告累积展示失败次数: $totalShowFailCount")
//
//                reportAdData(
//                    eventName = "ad_show_fail",
//                    params = mapOf(
//                        "ad_unit_name" to finalAdUnitId,
//                        "position" to PositionGet.get(),
//                        "number" to totalShowFailCount,
//                        "reason" to interceptResult.error.message
//                    )
//                )
//
//                return interceptResult
//            }
//            else -> { /* continue */ }
//        }

        return try {
            // 1. 尝试从缓存获取广告
            var cachedAd = getCachedAd(finalAdUnitId)

            // 2. 如果缓存为空，立即加载并缓存一个广告
            if (cachedAd == null) {
                // 激励广告阻塞loading
                ADLoadingDialog.show(activity)
                AdLogger.d("Admob缓存为空，立即加载激励广告，广告位ID: %s", finalAdUnitId)
                loadAdToCache(activity, finalAdUnitId)
                cachedAd = getCachedAd(finalAdUnitId)
            }

            if (cachedAd != null) {
                ADLoadingDialog.hide()
                AdLogger.d("Admob使用缓存中的激励广告，广告位ID: %s", finalAdUnitId)

                // 3. 显示广告
                val result = showAdInternal(activity, cachedAd.ad, finalAdUnitId, onRewardEarned, closeCallback)

                result
            } else {
                AdResult.Failure(createAdException("广告加载失败"))
            }
        } catch (e: Exception) {
            AdLogger.e("Admob显示激励广告异常", e)
            AdResult.Failure(createAdException("显示广告异常: ${e.message}", e))
        } finally {
            ADLoadingDialog.hide()
        }
    }

    /**
     * 基础广告加载方法（可复用）
     */
    private suspend fun loadAd(context: Context, adUnitId: String): RewardedAd? {
        // 累积加载次数统计
        totalLoadCount++
        AdLogger.d("Admob激励广告累积加载次数: $totalLoadCount")

        reportAdData(
            eventName = "ad_start_load",
            params = mapOf(
                "ad_unit_name" to adUnitId,
                "number" to totalLoadCount
            )
        )

        return suspendCancellableCoroutine { continuation ->
            val startTime = System.currentTimeMillis()

            val adRequest = AdRequest.Builder()
                .setHttpTimeoutMillis(7000) // 7秒超时
                .build()

            RewardedAd.load(context, adUnitId, adRequest, object : RewardedAdLoadCallback() {
                override fun onAdLoaded(rewardedAd: RewardedAd) {
                    val loadTime = System.currentTimeMillis() - startTime
                    AdLogger.d("Admob激励广告加载成功，广告位ID: %s, 耗时: %dms", adUnitId, loadTime)
                    totalLoadSucCount++
                    reportAdData(
                        eventName = "ad_loaded",
                        params = mapOf(
                            "ad_unit_name" to adUnitId,
                            "number" to totalLoadSucCount,
                            "ad_source" to (rewardedAd.responseInfo?.loadedAdapterResponseInfo?.adSourceName.orEmpty()),
                            "pass_time" to ceil(loadTime / 1000.0).toInt()
                        )
                    )

                    // 设置收益监听器
                    rewardedAd.onPaidEventListener = OnPaidEventListener { adValue ->
                        AdLogger.d("Admob激励广告收益回调: value=${adValue.valueMicros}, currency=${adValue.currencyCode}")

                        // 存储当前广告的收益信息
                        currentAdValue = adValue

                        reportAdData(
                            eventName = "ad_impression",
                            params = mapOf(
                                "ad_unit_name" to adUnitId,
                                "position" to PositionGet.get(),
                                "number" to totalShowCount,
                                "ad_source" to (rewardedAd.responseInfo?.loadedAdapterResponseInfo?.adSourceName.orEmpty()),
                                "value" to (currentAdValue?.let { it.valueMicros / 1_000_000.0 }
                                    ?: 0.0),
                                "currency" to (currentAdValue?.currencyCode ?: "")
                            )
                        )

                        // 上报真实的广告收益数据
                        reportAdRevenueWithValue(rewardedAd, adValue)

                        val revenueUsd = (adValue.valueMicros / 1_000_000.0).toLong()
                    }

                    continuation.resume(rewardedAd)
                }

                override fun onAdFailedToLoad(loadAdError: LoadAdError) {
                    val loadTime = System.currentTimeMillis() - startTime
                    AdLogger.e(
                        "Admob激励广告加载失败，广告位ID: %s, 耗时: %dms, 错误: %s",
                        adUnitId,
                        loadTime,
                        loadAdError.message
                    )

                    reportAdData(
                        eventName = "ad_load_fail",
                        params = mapOf(
                            "ad_unit_name" to adUnitId,
                            "number" to totalLoadSucCount,
                            "ad_source" to (loadAdError.responseInfo?.loadedAdapterResponseInfo?.adSourceName.orEmpty()),
                            "pass_time" to ceil(loadTime / 1000.0).toInt(),
                            "reason" to loadAdError.message
                        )
                    )

                    continuation.resume(null)
                }
            })
        }
    }

    /**
     * 加载广告到缓存
     */
    suspend fun loadAdToCache(context: Context, adUnitId: String): AdResult<Unit> {
        return try {

            // 检查缓存是否已满
            val currentAdUnitCount = getCachedAdCount(adUnitId)
            if (currentAdUnitCount >= maxCacheSizePerAdUnit) {
                AdLogger.w("Admob广告位 %s 缓存已满，当前缓存: %d/%d", adUnitId, currentAdUnitCount, maxCacheSizePerAdUnit)
                return AdResult.Success(Unit)
            }

            // 加载广告
            val rewardedAd = loadAd(context, adUnitId)
            if (rewardedAd != null) {
                synchronized(adCachePool) {
                    adCachePool.add(CachedRewardedAd(rewardedAd, adUnitId))
                    val currentCount = getCachedAdCount(adUnitId)
                    AdLogger.d(
                        "Admob激励广告加载成功并缓存，广告位ID: %s，该广告位缓存数量: %d/%d",
                        adUnitId,
                        currentCount,
                        maxCacheSizePerAdUnit
                    )
                }
                AdResult.Success(Unit)
            } else {
                AdResult.Failure(createAdException("广告加载失败"))
            }
        } catch (e: Exception) {
            AdLogger.e("Admob激励loadAdToCache异常", e)
            AdResult.Failure(AdException(0, "加载异常: ${e.message}", e))
        }
    }

    /**
     * 从缓存获取广告
     */
    private fun getCachedAd(adUnitId: String): CachedRewardedAd? {
        synchronized(adCachePool) {
            val index = adCachePool.indexOfFirst { it.adUnitId == adUnitId && !it.isExpired() }
            return if (index != -1) {
                adCachePool.removeAt(index)
            } else {
                null
            }
        }
    }

    fun peekCachedAd(adUnitId: String = BuildConfig.ADMOB_REWARDED_ID): RewardedAd? {
        return synchronized(adCachePool) {
            adCachePool.firstOrNull { it.adUnitId == adUnitId && !it.isExpired() }?.ad
        }
    }

    /**
     * 获取指定广告位的缓存数量
     */
    private fun getCachedAdCount(adUnitId: String): Int {
        synchronized(adCachePool) {
            return adCachePool.count { it.adUnitId == adUnitId && !it.isExpired() }
        }
    }

    /**
     * 检查指定广告位缓存是否已满
     */
    private fun isCacheFull(adUnitId: String): Boolean {
        return getCachedAdCount(adUnitId) >= maxCacheSizePerAdUnit
    }

    /**
     * 显示广告的内部实现
     */
    private suspend fun showAdInternal(
        activity: Activity,
        rewardedAd: RewardedAd,
        adUnitId: String,
        onRewardEarned: ((RewardItem, CommonRewardedData) -> Unit)?,
        closeCallback: () -> Unit
    ): AdResult<Unit> {
        return suspendCancellableCoroutine { continuation ->
            var hasRewarded = false
            rewardedAd.fullScreenContentCallback = object : FullScreenContentCallback() {
                override fun onAdDismissedFullScreenContent() {
                    AdLogger.d("Admob激励广告关闭")

                    // 设置广告不再显示标识
                    isShowing = false

                    totalCloseCount++

                    reportAdData(
                        eventName = "ad_close",
                        params = mapOf(
                            "ad_unit_name" to adUnitId,
                            "position" to PositionGet.get(),
                            "number" to totalCloseCount,
                            "ad_source" to (rewardedAd.responseInfo?.loadedAdapterResponseInfo?.adSourceName.orEmpty()),
                            "value" to (currentAdValue?.let { it.valueMicros / 1_000_000.0 }
                                ?: 0.0),
                            "currency" to (currentAdValue?.currencyCode ?: ""),
                            "isended" to if (hasRewarded) "true" else ""
                        )
                    )

                    val result = AdResult.Success(Unit)
                    if (continuation.isActive) {
                        continuation.resume(result)
                    }

                    closeCallback.invoke()
                }

                override fun onAdFailedToShowFullScreenContent(adError: AdError) {
                    AdLogger.w("Admob激励广告显示失败: %s", adError.message)

                    // 累积展示失败次数统计
                    totalShowFailCount++
                    AdLogger.d("Admob激励广告累积展示失败次数: $totalShowFailCount")

                    reportAdData(
                        eventName = "ad_show_fail",
                        params = mapOf(
                            "ad_unit_name" to adUnitId,
                            "position" to PositionGet.get(),
                            "number" to totalShowFailCount,
                            "ad_source" to (rewardedAd.responseInfo?.loadedAdapterResponseInfo?.adSourceName.orEmpty()),
                            "reason" to adError.message
                        )
                    )

                    val result = AdResult.Failure(createAdException("显示失败: ${adError.message}"))
                    if (continuation.isActive) {
                        continuation.resume(result)
                    }
                }

                override fun onAdShowedFullScreenContent() {
                    AdLogger.d("Admob激励广告开始显示")

                    AdConfigManager.getRewardedConfig()?.recordShow()
                }

                override fun onAdClicked() {
                    AdLogger.d("Admob激励广告被点击")

                    // 累积点击统计
                    totalClickCount++
                    AdLogger.d("Admob激励广告累积点击次数: $totalClickCount")

                    AdConfigManager.getRewardedConfig()?.recordClick()

                    reportAdData(
                        eventName = "ad_click",
                        params = mapOf(
                            "ad_unit_name" to adUnitId,
                            "position" to PositionGet.get(),
                            "number" to totalClickCount,
                            "ad_source" to (rewardedAd.responseInfo?.loadedAdapterResponseInfo?.adSourceName.orEmpty()),
                            "value" to (currentAdValue?.let { it.valueMicros / 1_000_000.0 }
                                ?: 0.0),
                            "currency" to (currentAdValue?.currencyCode ?: "")
                        )
                    )
                }

                override fun onAdImpression() {
                    AdLogger.d("Admob激励广告展示完成")

                    // 设置广告正在显示标识
                    isShowing = true

                    // 累积展示统计
                    totalShowCount++
                    AdLogger.d("Admob激励广告累积展示次数: $totalShowCount")

                    // 异步预加载下一个广告到缓存（如果缓存未满）
                    if (!isCacheFull(adUnitId)) {
                        PreloadController.preload(activity)
                    }
                }
            }

            // 设置奖励获得监听器
            val onUserEarnedRewardListener = OnUserEarnedRewardListener { rewardItem ->
                AdLogger.d("用户获得奖励: type=${rewardItem.type}, amount=${rewardItem.amount}")

                // 累积奖励获得次数统计
                totalRewardEarnedCount++
                AdLogger.d("激励广告累积奖励获得次数: $totalRewardEarnedCount")
                hasRewarded = true

                reportAdData(
                    eventName = "ad_reward_earned",
                    params = mapOf(
                        "ad_unit_name" to adUnitId,
                        "position" to PositionGet.get(),
                        "number" to totalRewardEarnedCount,
                        "reward_type" to rewardItem.type,
                        "reward_amount" to rewardItem.amount,
                        "ad_source" to (rewardedAd.responseInfo?.loadedAdapterResponseInfo?.adSourceName.orEmpty())
                    )
                )

                // 调用外部回调
                onRewardEarned?.invoke(rewardItem, CommonRewardedData(currentAdValue?.valueMicros?.toDouble() ?: 0.0))
            }

            rewardedAd.show(activity, onUserEarnedRewardListener)
        }
    }

    /**
     * 销毁广告
     */
    fun destroyAd() {
        synchronized(adCachePool) {
            adCachePool.clear()
        }
        AdLogger.d("激励广告已销毁")
    }

    /**
     * 上报广告收益数据（使用真实收益值）
     * @param rewardedAd 激励广告对象
     * @param adValue 广告收益值
     */
    private fun reportAdRevenueWithValue(rewardedAd: RewardedAd, adValue: AdValue) {
        // 创建广告收益数据
        val adRevenueData = AdRevenueData(
            revenue = RevenueInfo(
                value = adValue.valueMicros / 1_000_000.0,
                currencyCode = adValue.currencyCode
            ),
            adRevenueNetwork = rewardedAd.responseInfo.loadedAdapterResponseInfo?.adSourceName.orEmpty(),
            adRevenueUnit = rewardedAd.adUnitId,
            adRevenuePlacement = rewardedAd.responseInfo.loadedAdapterResponseInfo?.adSourceInstanceName.orEmpty(),
            adFormat = "Rewarded"
        )

        // 上报收益数据（内部已处理初始化和异常）
        AdRevenueManager.reportAdRevenue(adRevenueData)
        AdLogger.d("激励广告真实收益数据已上报，广告位ID: ${rewardedAd.adUnitId}, 收益: ${adValue.valueMicros}微元 ${adValue.currencyCode}")
    }

    /**
     * 销毁控制器
     */
    fun destroy() {
        destroyAd()
        AdLogger.d("激励广告控制器已清理")
    }

    /**
     * 通用数据上报函数
     * @param eventName 事件名称
     * @param params 参数Map，会与基础参数合并
     */
    private fun reportAdData(eventName: String, params: Map<String, Any>) {
        val data = mutableMapOf<String, Any>(
            "ad_platform" to "Admob",
            "ad_format" to "Rewarded"
        )

        // 直接合并传入的参数
        data.putAll(params)

        if(eventName == "ad_impression"){
            DataReportManager.reportDataByName("ThinkingData",eventName, data)
        } else{
            DataReportManager.reportData(eventName, data)
        }
    }

    /**
     * 创建广告异常
     */
    private fun createAdException(message: String, cause: Throwable? = null): AdException {
        return AdException(
            code = 0,
            message = message,
            cause = cause
        )
    }

    /**
     * 获取激励广告是否正在显示的状态
     * @return true 如果激励广告正在显示，false 否则
     */
    fun isAdShowing(): Boolean {
        return isShowing
    }
}