package com.remax.bill.ads.topon

import android.app.Activity
import android.content.Context
import android.view.ViewGroup
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.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.splashad.api.TUSplashAd
import com.thinkup.splashad.api.TUSplashAdEZListener
import com.thinkup.splashad.api.TUSplashAdExtraInfo
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 TopOnSplashAdController private constructor() {

    // 累积统计（持久化）
    private var totalClickCount by KvIntDelegate("topon_splash_ad_total_clicks", 0)
    private var totalCloseCount by KvIntDelegate("topon_splash_ad_total_close", 0)
    private var totalLoadCount by KvIntDelegate("topon_splash_ad_total_loads", 0)
    private var totalLoadSucCount by KvIntDelegate("topon_splash_ad_total_load_suc", 0)
    private var totalShowFailCount by KvIntDelegate("topon_splash_ad_total_show_fails", 0)
    private var totalShowTriggerCount by KvIntDelegate("topon_splash_ad_total_show_triggers", 0)
    private var totalShowCount by KvIntDelegate("topon_splash_ad_total_shows", 0)

    companion object {
        private const val TAG = "TopOnSplashAdController"
        private const val AD_TIMEOUT = 4 * 60 * 60 * 1000L // 4小时过期
        private const val DEFAULT_CACHE_SIZE_PER_AD_UNIT = 1
        private const val DEFAULT_FETCH_AD_TIMEOUT = 8000 // 8秒超时

        @Volatile
        private var INSTANCE: TopOnSplashAdController? = null

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

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

    // 存储每个 placementId 对应的 continuation，用于在 onAdDismiss 回调中恢复
    private val continuationMap = mutableMapOf<String, kotlinx.coroutines.CancellableContinuation<AdResult<Unit>>>()

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

    /**
     * 缓存的开屏广告数据类
     */
    private data class CachedSplashAd(
        val splashAd: TUSplashAd,
        val placementId: String,
        val loadTime: Long = System.currentTimeMillis()
    ) {
        fun isExpired(): Boolean {
            return System.currentTimeMillis() - loadTime > AD_TIMEOUT || !splashAd.isAdReady
        }
    }

    /**
     * 预加载开屏广告
     * @param context 上下文
     * @param placementId 广告位ID，如果为空则使用默认ID
     */
    suspend fun preloadAd(context: Context, placementId: String? = null): AdResult<Unit> {
        if (!GlobalAdSwitchInterceptor.isGlobalAdEnabled()) {
            return AdResult.Failure(
                AdException(
                    code = -100,
                    message = "开屏全局广告已关闭，中断加载"
                )
            )
        }
        val finalPlacementId = placementId ?: BuildConfig.TOPON_SPLASH_ID
        return loadAdToCache(context, finalPlacementId)
    }

    /**
     * 基础广告加载方法（可复用）
     */
    private suspend fun loadAd(context: Context, placementId: String, fetchAdTimeout: Int = DEFAULT_FETCH_AD_TIMEOUT): TUSplashAd? {
        // 累积加载次数统计
        totalLoadCount++
        AdLogger.d("TopOn开屏广告累积加载次数: $totalLoadCount")

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

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

            // 将 splashAd 声明在外部作用域，以便在回调中访问
            var splashAd: TUSplashAd? = null

            try {
                splashAd = TUSplashAd(
                    applicationContext,
                    placementId,
                    object : TUSplashAdEZListener() {
                        override fun onAdLoaded() {
                            val loadTime = System.currentTimeMillis() - startTime
                            AdLogger.d("TopOn开屏广告加载成功，广告位ID: %s, 耗时: %dms", placementId, loadTime)
                            totalLoadSucCount++
                            reportAdData(
                                eventName = "ad_loaded",
                                params = mapOf(
                                    "ad_unit_name" to placementId,
                                    "number" to totalLoadSucCount,
                                    "ad_source" to "",
                                    "pass_time" to ceil(loadTime / 1000.0).toInt()
                                )
                            )
                            continuation.resume(splashAd)
                        }

                        override fun onNoAdError(adError: AdError) {
                            val loadTime = System.currentTimeMillis() - startTime
                            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())
                                )
                            )
                            continuation.resume(null)
                        }

                        override fun onAdShow(adInfo: TUAdInfo) {
                            AdLogger.d("TopOn开屏广告开始显示")
                            totalShowCount++
                            AdLogger.d("TopOn开屏广告累积展示次数: $totalShowCount")
                            AdConfigManager.getAppOpenConfig().recordShow()
                            
                            // 处理收益信息
                            val revenueValue = adInfo.publisherRevenue ?: adInfo.ecpm ?: 0.0
                            val revenueCurrency = adInfo.currency ?: "USD"
                            
                            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 revenueValue,
                                    "currency" to revenueCurrency
                                )
                            )
                            
                            // 上报真实的广告收益数据
                            splashAd?.let {
                                reportAdRevenueWithValue(it, adInfo, placementId)
                            }
                            
                            // TopOn 的 revenueValue 已经是美元，直接使用
                            val revenueUsd = revenueValue.toLong()
                        }

                        override fun onAdClick(adInfo: TUAdInfo) {
                            AdLogger.d("TopOn开屏广告被点击")
                            totalClickCount++
                            AdLogger.d("TopOn开屏广告累积点击次数: $totalClickCount")
                            AdConfigManager.getAppOpenConfig().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 "USD"
                                )
                            )
                        }


                        override fun onAdDismiss(adInfo: TUAdInfo, splashAdExtraInfo: TUSplashAdExtraInfo) {
                            AdLogger.d("TopOn开屏广告关闭")
                            totalCloseCount++
                            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 ?: adInfo.ecpm ?: 0.0),
                                    "currency" to (adInfo.currency ?: "USD")
                                )
                            )

                            // 恢复 continuation（在 showAdInternal 中设置）
                            synchronized(continuationMap) {
                                continuationMap.remove(placementId)?.let { cont ->
                                    if (cont.isActive) {
                                        cont.resume(AdResult.Success(Unit))
                                    }
                                }
                            }
                            
                            // 广告关闭后，如果缓存未满，异步预加载下一个广告
                            if (!isCacheFull(placementId)) {
                                AdLogger.d("TopOn开屏广告关闭后开始异步预加载下一个广告，广告位ID: %s", placementId)
                                CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
                                    try {
                                        preloadAd(applicationContext, placementId)
                                    } catch (e: Exception) {
                                        AdLogger.e("TopOn开屏广告预加载失败", e)
                                    }
                                }
                            }
                        }
                    },
                    fetchAdTimeout
                )

                splashAd.loadAd()
            } catch (e: Exception) {
                AdLogger.e("TopOn开屏广告加载异常", e)
                if (continuation.isActive) {
                    continuation.resume(null)
                }
            }
        }
    }

    /**
     * 加载广告到缓存
     */
    suspend fun loadAdToCache(context: Context, placementId: String): AdResult<Unit> {
        return try {
            // 检查缓存是否已满
            val currentPlacementCount = getCachedAdCount(placementId)
            if (currentPlacementCount >= maxCacheSizePerAdUnit) {
                AdLogger.w("广告位 %s 缓存已满，当前缓存: %d/%d", placementId, currentPlacementCount, maxCacheSizePerAdUnit)
                return AdResult.Success(Unit)
            }

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

    /**
     * 显示开屏广告（自动处理加载和过期检查）
     * @param activity Activity上下文
     * @param placementId 广告位ID，如果为空则使用默认ID
     * @param onLoaded 加载状态回调
     */
    suspend fun showAd(
        activity: Activity,
        placementId: String = BuildConfig.TOPON_SPLASH_ID,
        onLoaded: ((isSuc: Boolean) -> Unit)? = null
    ): AdResult<Unit> {
        // 累积触发广告展示次数统计
        totalShowTriggerCount++
        AdLogger.d("TopOn开屏广告累积触发展示次数: $totalShowTriggerCount")

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

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

        val finalPlacementId = placementId
        val adResult = try {
            // 1. 尝试从缓存获取广告
            var cachedAd = getCachedAd(finalPlacementId)

            // 2. 如果缓存为空，立即加载并缓存一个广告
            if (cachedAd == null) {
                AdLogger.d("缓存为空，立即加载TopOn开屏广告，广告位ID: %s", finalPlacementId)
                loadAdToCache(activity, finalPlacementId)
                cachedAd = getCachedAd(finalPlacementId)
            }

            if (cachedAd != null) {
                AdLogger.d("使用缓存中的TopOn开屏广告，广告位ID: %s", finalPlacementId)
                onLoaded?.invoke(true)

                // 3. 获取容器并显示广告
                val container = activity.window.decorView.findViewById<ViewGroup>(android.R.id.content)
                    ?: activity.window.decorView as ViewGroup
                val result = showAdInternal(activity, container, cachedAd.splashAd, finalPlacementId)

                result
            } else {
                onLoaded?.invoke(false)
                AdResult.Failure(createAdException("广告加载失败"))
            }
        } catch (e: Exception) {
            AdLogger.e("显示TopOn开屏广告异常", e)
            AdResult.Failure(createAdException("显示广告异常: ${e.message}", e))
        }

        return adResult
    }

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

    fun peekCachedAd(placementId: String = BuildConfig.TOPON_SPLASH_ID): TUSplashAd? {
        return synchronized(adCachePool) {
            adCachePool.firstOrNull { it.placementId == placementId && !it.isExpired() }?.splashAd
        }
    }

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

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

    /**
     * 显示广告的内部实现
     */
    private suspend fun showAdInternal(
        activity: Activity,
        container: ViewGroup,
        splashAd: TUSplashAd,
        placementId: String
    ): AdResult<Unit> {
        return suspendCancellableCoroutine { continuation ->
            try {
                // 检查广告是否准备好
                if (!splashAd.isAdReady) {
                    AdLogger.w("TopOn开屏广告未准备好，广告位ID: %s", placementId)
                    totalShowFailCount++
                    reportAdData(
                        eventName = "ad_show_fail",
                        params = mapOf(
                            "ad_unit_name" to placementId,
                            "position" to PositionGet.get(),
                            "number" to totalShowFailCount,
                            "reason" to "广告未准备好"
                        )
                    )
                    if (continuation.isActive) {
                        continuation.resume(AdResult.Failure(createAdException("广告未准备好")))
                    }
                    return@suspendCancellableCoroutine
                }

                // 存储 continuation，以便在 onAdDismiss 回调中使用
                synchronized(continuationMap) {
                    continuationMap[placementId] = continuation
                }

                // 显示广告
                // onAdDismiss 回调已在 loadAd 中设置，会在广告关闭时恢复 continuation
                splashAd.show(activity, container)
            } catch (e: Exception) {
                AdLogger.e("TopOn开屏广告显示异常", e)
                totalShowFailCount++
                reportAdData(
                    eventName = "ad_show_fail",
                    params = mapOf(
                        "ad_unit_name" to placementId,
                        "position" to PositionGet.get(),
                        "number" to totalShowFailCount,
                        "reason" to (e.message ?: "显示异常")
                    )
                )
                // 清理 continuation
                synchronized(continuationMap) {
                    continuationMap.remove(placementId)
                }
                if (continuation.isActive) {
                    continuation.resume(AdResult.Failure(createAdException("显示失败: ${e.message}", e)))
                }
            }
        }
    }

    /**
     * 上报广告收益数据（使用真实收益值）
     * @param splashAd 开屏广告对象
     * @param adInfo 广告信息
     * @param placementId 广告位ID
     */
    private fun reportAdRevenueWithValue(splashAd: TUSplashAd, adInfo: TUAdInfo, placementId: String) {
        // 创建广告收益数据
        val adRevenueData = AdRevenueData(
            revenue = RevenueInfo(
                value = adInfo.publisherRevenue ?: 0.0,
                currencyCode = "USD"
            ),
            adRevenueNetwork = adInfo.networkName ?: "",
            adRevenueUnit = placementId,
            adRevenuePlacement = adInfo.placementId ?: "",
            adFormat = "Splash"
        )

        // 上报收益数据（内部已处理初始化和异常）
        AdRevenueManager.reportAdRevenue(adRevenueData)
        AdLogger.d("TopOn开屏广告真实收益数据已上报，广告位ID: %s, 收益: %.8f USD", placementId, adInfo.publisherRevenue ?: 0.0)
    }

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

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

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

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

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

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

