package com.remax.bill.ads.topon

import android.app.Activity
import android.content.Context
import com.remax.bill.BuildConfig
import com.remax.bill.ads.AdException
import com.remax.bill.ads.AdResult
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.bill.ads.log.AdLogger
import com.remax.bill.ads.util.PositionGet
import com.remax.bill.ui.dialog.ADLoadingDialog
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.thinkup.core.api.AdError
import com.thinkup.core.api.TUAdInfo
import com.thinkup.core.api.TUAdRevenueListener
import com.thinkup.rewardvideo.api.TURewardVideoAd
import com.thinkup.rewardvideo.api.TURewardVideoListener
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.math.ceil

/**
 * TopOn 激励广告控制器
 * 参考 AdMob 激励广告控制器实现，保持埋点和收益上报一致
 */
class TopOnRewardedAdController private constructor() {

    // 累积统计（持久化）
    private var totalClickCount by KvIntDelegate("topon_rewarded_ad_total_clicks", 0)
    private var totalCloseCount by KvIntDelegate("topon_rewarded_ad_total_close", 0)
    private var totalLoadCount by KvIntDelegate("topon_rewarded_ad_total_loads", 0)
    private var totalLoadSucCount by KvIntDelegate("topon_rewarded_ad_total_load_suc", 0)
    private var totalShowFailCount by KvIntDelegate("topon_rewarded_ad_total_show_fails", 0)
    private var totalShowTriggerCount by KvIntDelegate("topon_rewarded_ad_total_show_triggers", 0)
    private var totalShowCount by KvIntDelegate("topon_rewarded_ad_total_shows", 0)
    private var totalRewardEarnedCount by KvIntDelegate("topon_rewarded_ad_total_reward_earned", 0)

    // 是否正在展示
    @Volatile
    private var isShowing: Boolean = false

    companion object {
        private const val CACHE_EXPIRE_MS = 60 * 60 * 1000L

        @Volatile
        private var INSTANCE: TopOnRewardedAdController? = null

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

    private val interceptorChain = InterceptorChain(
        listOf(
            GlobalAdSwitchInterceptor(),
            ShowCountLimitInterceptor(),
            ShowIntervalLimitInterceptor(),
            ClickLimitInterceptor()
        )
    )

    private val adCache = mutableMapOf<String, TopOnRewardedAdEntry>()

    /**
     * 缓存的激励广告实体
     */
    private data class TopOnRewardedAdEntry(
        val placementId: String,
        val ad: TURewardVideoAd,
        val listener: TopOnRewardedVideoListener,
        val cacheTime: Long = System.currentTimeMillis()
    ) {
        fun isExpired(): Boolean {
            return System.currentTimeMillis() - cacheTime > CACHE_EXPIRE_MS || !ad.isAdReady
        }
    }

    /**
     * 预加载广告
     */
    suspend fun preloadAd(context: Context, placementId: String? = null): AdResult<Unit> {
        if (!GlobalAdSwitchInterceptor.isGlobalAdEnabled()) {
            return AdResult.Failure(
                AdException(
                    code = -100,
                    message = "全局广告开关关闭，终止加载"
                )
            )
        }

        val finalPlacementId = resolvePlacementId(placementId)
        if (finalPlacementId.isBlank()) {
            AdLogger.w("TopOn激励广告缺少有效的广告位ID，无法预加载")
            return AdResult.Failure(createAdException("广告位ID缺失"))
        }

        val cached = synchronized(adCache) {
            adCache[finalPlacementId]?.takeUnless { it.isExpired() }
        }
        if (cached != null) {
            AdLogger.d("TopOn激励广告已有有效缓存，广告位ID: %s", finalPlacementId)
            return AdResult.Success(Unit)
        }

        return if (loadAd(context, finalPlacementId) != null) {
            AdResult.Success(Unit)
        } else {
            AdResult.Failure(createAdException("广告加载失败"))
        }
    }

    /**
     * 展示广告
     */
    suspend fun showAd(
        activity: Activity,
        placementId: String? = null,
        onRewardEarned: ((String, Int, Double) -> Unit)? = null,
        closeCallback: ()->Unit
    ): AdResult<Unit> {
        val finalPlacementId = resolvePlacementId(placementId)
        if (finalPlacementId.isBlank()) {
            return AdResult.Failure(createAdException("广告位ID缺失"))
        }

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

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

        // 拦截器检查（激励广告通常不拦截，但保留逻辑）
        // when (val interceptResult = interceptorChain.intercept(activity, AdConfigManager.getRewardedConfig())) {
        //     is AdResult.Failure -> {
        //         totalShowFailCount++
        //         AdLogger.d("TopOn激励广告拦截后累积展示失败次数: $totalShowFailCount")
        //         reportAdData(
        //             eventName = "ad_show_fail",
        //             params = mapOf(
        //                 "ad_unit_name" to finalPlacementId,
        //                 "position" to PositionGet.get(),
        //                 "number" to totalShowFailCount,
        //                 "reason" to interceptResult.error.message
        //             )
        //         )
        //         return interceptResult
        //     }
        //     else -> Unit
        // }

        return try {
            var entry = synchronized(adCache) {
                adCache[finalPlacementId]?.takeUnless { it.isExpired() }
            }

            if (entry == null) {
                ADLoadingDialog.show(activity)
                loadAd(activity, finalPlacementId)
                entry = synchronized(adCache) {
                    adCache[finalPlacementId]?.takeUnless { it.isExpired() }
                }
            }

            if (entry != null && entry.ad.isAdReady) {
                ADLoadingDialog.hide()
                AdLogger.d("TopOn使用缓存激励广告展示，广告位ID: %s", finalPlacementId)
                entry.listener.awaitShow(activity, onRewardEarned, closeCallback)
            } else {
                ADLoadingDialog.hide()
                AdResult.Failure(createAdException("广告加载失败"))
            }
        } catch (e: Exception) {
            AdLogger.e("TopOn激励广告展示异常", e)
            AdResult.Failure(createAdException("显示广告异常: ${e.message}", e))
        } finally {
            ADLoadingDialog.hide()
        }
    }

    /**
     * 加载广告
     */
    private suspend fun loadAd(context: Context, placementId: String): TopOnRewardedAdEntry? {
        totalLoadCount++
        AdLogger.d("TopOn激励广告开始加载，广告位ID: %s，当前累计加载次数: %d", placementId, totalLoadCount)

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

        return suspendCancellableCoroutine { continuation ->
            try {
                val applicationContext = context.applicationContext
                val rewardedVideoAd = TURewardVideoAd(applicationContext, placementId)
                val listener = TopOnRewardedVideoListener(
                    placementId = placementId,
                    startLoadTime = System.currentTimeMillis(),
                    rewardedVideoAd = rewardedVideoAd,
                    applicationContext = applicationContext
                )
                listener.attachLoadContinuation(continuation)

                rewardedVideoAd.setAdListener(listener)
                rewardedVideoAd.setAdRevenueListener(listener)

                continuation.invokeOnCancellation {
                    listener.clearLoadContinuation()
                }

                rewardedVideoAd.load(applicationContext)
            } catch (e: Exception) {
                AdLogger.e("TopOn激励广告加载异常", e)
                if (continuation.isActive) {
                    continuation.resume(null)
                }
            }
        }
    }

    /**
     * 销毁广告缓存
     */
    private fun destroyAd() {
        synchronized(adCache) {
            adCache.clear()
        }
        AdLogger.d("TopOn激励广告缓存已清理")
    }

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

    /**
     * 获取激励广告是否正在展示
     */
    fun isAdShowing(): Boolean {
        return isShowing
    }

    /**
     * 获取当前缓存的广告对象（用于竞价）
     */
    fun getCurrentAd(placementId: String? = null): com.thinkup.rewardvideo.api.TURewardVideoAd? {
        val finalPlacementId = resolvePlacementId(placementId)
        if (finalPlacementId.isBlank()) {
            return null
        }
        
        return synchronized(adCache) {
            adCache[finalPlacementId]?.takeUnless { it.isExpired() }?.ad
        }
    }

    /**
     * TopOn 激励视频广告监听器
     */
    private inner class TopOnRewardedVideoListener(
        private val placementId: String,
        private val startLoadTime: Long,
        private val rewardedVideoAd: TURewardVideoAd,
        private val applicationContext: Context
    ) : TURewardVideoListener, TUAdRevenueListener {

        private var loadContinuation: kotlinx.coroutines.CancellableContinuation<TopOnRewardedAdEntry?>? = null
        private var showContinuation: kotlinx.coroutines.CancellableContinuation<AdResult<Unit>>? = null
        private var lastAdInfo: TUAdInfo? = null
        private var cacheTime: Long = System.currentTimeMillis()
        private var hasRewarded: Boolean = false
        private var rewardCallback: ((String, Int, Double) -> Unit)? = null
        private var closeCallback: (()->Unit)? = null

        fun attachLoadContinuation(continuation: kotlinx.coroutines.CancellableContinuation<TopOnRewardedAdEntry?>) {
            loadContinuation = continuation
        }

        fun clearLoadContinuation() {
            loadContinuation = null
        }

        private fun resumeLoad(entry: TopOnRewardedAdEntry?) {
            loadContinuation?.let { continuation ->
                if (continuation.isActive) {
                    continuation.resume(entry)
                }
            }
            loadContinuation = null
        }

        private fun resumeShow(result: AdResult<Unit>) {
            showContinuation?.let { continuation ->
                if (continuation.isActive) {
                    continuation.resume(result)
                }
            }
            showContinuation = null
        }

        suspend fun awaitShow(
            activity: Activity,
            onRewardEarned: ((String, Int, Double) -> Unit)?,
            closeCallback: () -> Unit
        ): AdResult<Unit> {
            if (!rewardedVideoAd.isAdReady) {
                AdLogger.w("TopOn激励广告未准备好，展示终止，广告位ID: %s", placementId)
                return AdResult.Failure(createAdException("广告未准备好"))
            }

            rewardCallback = onRewardEarned
            this.closeCallback = closeCallback
            hasRewarded = false

            return suspendCancellableCoroutine { continuation ->
                showContinuation = continuation
                continuation.invokeOnCancellation {
                    showContinuation = null
                }

                try {
                    rewardedVideoAd.show(activity)
                } catch (e: Exception) {
                    AdLogger.e("TopOn激励广告调用show异常", e)
                    if (continuation.isActive) {
                        continuation.resume(
                            AdResult.Failure(createAdException("显示失败: ${e.message}", e))
                        )
                    }
                    showContinuation = null
                }
            }
        }

        override fun onRewardedVideoAdLoaded() {
            val loadTime = System.currentTimeMillis() - startLoadTime
            totalLoadSucCount++
            cacheTime = System.currentTimeMillis()

            val adInfo = runCatching { rewardedVideoAd.checkValidAdCaches().firstOrNull() }.getOrNull()

            AdLogger.d(
                "TopOn激励广告加载成功，广告位ID: %s，耗时: %dms，缓存成功次数: %d",
                placementId,
                loadTime,
                totalLoadSucCount
            )

            reportAdData(
                eventName = "ad_loaded",
                params = mapOf(
                    "ad_unit_name" to placementId,
                    "number" to totalLoadSucCount,
                    "ad_source" to (adInfo?.networkName.orEmpty()),
                    "pass_time" to ceil(loadTime / 1000.0).toInt()
                )
            )

            val entry = TopOnRewardedAdEntry(
                placementId = placementId,
                ad = rewardedVideoAd,
                listener = this,
                cacheTime = cacheTime
            )

            synchronized(adCache) {
                adCache[placementId] = entry
            }

            resumeLoad(entry)
        }

        override fun onRewardedVideoAdFailed(adError: AdError) {
            val loadTime = System.currentTimeMillis() - startLoadTime
            AdLogger.e(
                "TopOn激励广告加载失败，广告位ID: %s，耗时: %dms，错误: %s",
                placementId,
                loadTime,
                adError.getFullErrorInfo()
            )

            reportAdData(
                eventName = "ad_load_fail",
                params = mapOf(
                    "ad_unit_name" to placementId,
                    "number" to totalLoadSucCount,
                    "ad_source" to "",
                    "pass_time" to ceil(loadTime / 1000.0).toInt(),
                    "reason" to (adError.desc ?: adError.getFullErrorInfo())
                )
            )

            resumeLoad(null)
        }

        override fun onRewardedVideoAdPlayStart(adInfo: TUAdInfo) {
            AdLogger.d("TopOn激励广告开始播放")
            isShowing = true
            lastAdInfo = adInfo
            AdConfigManager.getRewardedConfig()?.recordShow()
        }

        override fun onRewardedVideoAdPlayEnd(adInfo: TUAdInfo) {
            AdLogger.d("TopOn激励广告播放结束")
            lastAdInfo = adInfo
        }

        override fun onRewardedVideoAdPlayFailed(adError: AdError, adInfo: TUAdInfo?) {
            AdLogger.w("TopOn激励广告播放失败: %s", adError.desc ?: adError.getFullErrorInfo())
            isShowing = false
            totalShowFailCount++
            lastAdInfo = adInfo

            reportAdData(
                eventName = "ad_show_fail",
                params = mapOf(
                    "ad_unit_name" to placementId,
                    "position" to PositionGet.get(),
                    "number" to totalShowFailCount,
                    "ad_source" to (adInfo?.networkName ?: ""),
                    "reason" to (adError.desc ?: adError.getFullErrorInfo())
                )
            )

            synchronized(adCache) {
                adCache.remove(placementId)
            }

            resumeShow(AdResult.Failure(createAdException("播放失败: ${adError.desc ?: "unknown"}")))
        }

        override fun onRewardedVideoAdClosed(adInfo: TUAdInfo) {
            AdLogger.d("TopOn激励广告关闭")
            isShowing = false
            totalCloseCount++
            lastAdInfo = adInfo

            reportAdData(
                eventName = "ad_close",
                params = mapOf(
                    "ad_unit_name" to placementId,
                    "position" to PositionGet.get(),
                    "number" to totalCloseCount,
                    "ad_source" to (adInfo.networkName ?: ""),
                    "value" to (adInfo.publisherRevenue ?: 0.0),
                    "currency" to (adInfo.currency ?: ""),
                    "isended" to if (hasRewarded) "true" else ""
                )
            )

            synchronized(adCache) {
                adCache.remove(placementId)
            }

            // 激励关闭时重新预缓存
            CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
                try {
                    AdLogger.d("TopOn激励广告关闭，开始重新预缓存，广告位ID: %s", placementId)
                    preloadAd(applicationContext, placementId)
                } catch (e: Exception) {
                    AdLogger.e("TopOn激励广告重新预缓存失败", e)
                }
            }

            closeCallback?.invoke()
            resumeShow(AdResult.Success(Unit))
            reportAdRevenueWithValue(adInfo)
        }

        override fun onRewardedVideoAdPlayClicked(adInfo: TUAdInfo) {
            AdLogger.d("TopOn激励广告被点击")
            totalClickCount++
            lastAdInfo = adInfo
            AdLogger.d("TopOn激励广告累积点击次数: $totalClickCount")

            AdConfigManager.getRewardedConfig()?.recordClick()

            reportAdData(
                eventName = "ad_click",
                params = mapOf(
                    "ad_unit_name" to placementId,
                    "position" to PositionGet.get(),
                    "number" to totalClickCount,
                    "ad_source" to (adInfo.networkName ?: ""),
                    "value" to (adInfo.publisherRevenue ?: 0.0),
                    "currency" to (adInfo.currency ?: "")
                )
            )
        }

        override fun onReward(adInfo: TUAdInfo) {
            AdLogger.d("TopOn用户获得奖励")
            hasRewarded = true
            totalRewardEarnedCount++
            lastAdInfo = adInfo
            AdLogger.d("TopOn激励广告累积奖励获得次数: $totalRewardEarnedCount")

            val rewardType = adInfo.scenarioRewardName ?: "default"
            val rewardAmount = adInfo.scenarioRewardNumber

            reportAdData(
                eventName = "ad_reward_earned",
                params = mapOf(
                    "ad_unit_name" to placementId,
                    "position" to PositionGet.get(),
                    "number" to totalRewardEarnedCount,
                    "reward_type" to rewardType,
                    "reward_amount" to rewardAmount,
                    "ad_source" to (adInfo.networkName ?: "")
                )
            )
            var revenueValue = 0.0
            if ("USD" == adInfo.currency) {
                revenueValue = adInfo.publisherRevenue ?: 0.0
            }
            rewardCallback?.invoke(rewardType, rewardAmount, revenueValue)
        }

        override fun onAdRevenuePaid(adInfo: TUAdInfo) {
            lastAdInfo = adInfo
            totalShowCount++
            AdLogger.d(
                "TopOn激励广告收益回调，value=${adInfo.publisherRevenue ?: adInfo.ecpm}, currency=${adInfo.currency}"
            )

            reportAdData(
                eventName = "ad_impression",
                params = mapOf(
                    "ad_unit_name" to placementId,
                    "position" to PositionGet.get(),
                    "number" to totalShowCount,
                    "ad_source" to (adInfo.networkName ?: ""),
                    "value" to (adInfo.publisherRevenue ?: 0.0),
                    "currency" to (adInfo.currency ?: "")
                )
            )

            val revenueValue = adInfo.publisherRevenue ?: 0.0
            // TopOn 的 revenueValue 已经是美元，不需要转换
            val revenueUsd = revenueValue.toLong()

            //reportAdRevenueWithValue(adInfo)
        }
    }

    /**
     * 上报广告收益
     */
    private fun reportAdRevenueWithValue(adInfo: TUAdInfo) {
        val revenueValue = adInfo.publisherRevenue ?: adInfo.ecpm
        val revenueCurrency = adInfo.currency ?: "USD"
        val adRevenueData = AdRevenueData(
            revenue = RevenueInfo(
                value = revenueValue,
                currencyCode = revenueCurrency
            ),
            adRevenueNetwork = adInfo.networkName ?: "",
            adRevenueUnit = adInfo.placementId ?: "",
            adRevenuePlacement = adInfo.scenarioId ?: "",
            adFormat = "Rewarded"
        )

        AdRevenueManager.reportAdRevenue(adRevenueData)
        AdLogger.d(
            "TopOn激励广告收益上报，placement=%s, revenue=%f %s",
            adInfo.placementId,
            revenueValue,
            revenueCurrency
        )
    }

    /**
     * 通用数据上报
     */
    private fun reportAdData(eventName: String, params: Map<String, Any>) {
        val data = mutableMapOf<String, Any>(
            "ad_platform" to "TopOn",
            "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
        )
    }

    /**
     * 解析广告位ID
     */
    private fun resolvePlacementId(placementId: String?): String {
        if (!placementId.isNullOrBlank()) {
            return placementId
        }

        return BuildConfig.TOPON_REWARDED_ID
    }
}

