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.bill.ui.topon.ToponBannerAdView
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.TUAdConst
import com.thinkup.core.api.TUAdInfo
import com.thinkup.banner.api.TUBannerView
import com.thinkup.banner.api.TUBannerListener
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 Banner 广告控制器
 * 参考 AdMob Banner 广告控制器实现，保持埋点一致
 * 参考文档: https://help.toponad.net/cn/docs/heng-fu-guang-gao
 */
class TopOnBannerAdController private constructor() {

    // 累积统计（持久化）
    private var totalClickCount by KvIntDelegate("topon_banner_total_clicks", 0)
    private var totalCloseCount by KvIntDelegate("topon_banner_total_close", 0)
    private var totalLoadCount by KvIntDelegate("topon_banner_total_loads", 0)
    private var totalLoadSucCount by KvIntDelegate("topon_banner_total_load_suc", 0)
    private var totalShowFailCount by KvIntDelegate("topon_banner_total_show_fails", 0)
    private var totalShowTriggerCount by KvIntDelegate("topon_banner_total_show_triggers", 0)
    private var totalShowCount by KvIntDelegate("topon_banner_total_shows", 0)

    companion object {
        private const val TAG = "TopOnBannerAdController"
        private const val AD_TIMEOUT = 1 * 60 * 60 * 1000L // 1小时过期
        private const val DEFAULT_CACHE_SIZE_PER_AD_UNIT = 1
        private const val BANNER_WIDTH_320 = 320 // 标准 Banner 宽度（dp）

        @Volatile
        private var INSTANCE: TopOnBannerAdController? = null

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

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

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

    private val bannerView = ToponBannerAdView()

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

    /**
     * 缓存的 Banner 广告数据类
     */
    private data class CachedBannerAd(
        val bannerView: TUBannerView,
        val placementId: String,
        val loadTime: Long = System.currentTimeMillis()
    ) {
        fun isExpired(): Boolean {
            return System.currentTimeMillis() - loadTime > AD_TIMEOUT
        }
    }

    /**
     * 创建 Banner 广告视图
     * @param activity Activity 上下文
     * @param placementId 广告位ID，如果为空则使用默认ID
     */
    fun createBannerAdView(activity: Activity, placementId: String? = null): TUBannerView {
        val finalPlacementId = placementId ?: BuildConfig.TOPON_BANNER_ID
        return TUBannerView(activity).apply {
            setPlacementId(finalPlacementId)
        }
    }

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

    /**
     * 显示 Banner 广告（自动处理加载）
     * @param activity Activity 上下文
     * @param container 目标容器
     * @param placementId 广告位ID，如果为空则使用默认ID
     */
    suspend fun showAd(
        activity: Activity,
        container: ViewGroup,
        placementId: String? = null
    ): AdResult<TUBannerView> {
        val finalPlacementId = placementId ?: BuildConfig.TOPON_BANNER_ID

        // 累积触发统计
        totalShowTriggerCount++
        AdLogger.d("TopOn Banner 广告累积触发展示次数: $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.getBannerConfig())) {
            is AdResult.Failure -> {
                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 AdResult.Failure(interceptResult.error)
            }
            else -> { /* continue */ }
        }

        return try {
            // 1. 尝试从缓存获取广告
            var cachedAd = getCachedAd(finalPlacementId)
            if (cachedAd == null) {
                AdLogger.d("缓存为空，立即加载 TopOn Banner 广告，广告位ID: %s", finalPlacementId)
                loadAdToCache(activity, finalPlacementId)
                cachedAd = getCachedAd(finalPlacementId)
            }

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

                // 绑定广告到容器
                val success = bannerView.bindBannerAdToContainer(
                    activity, container, cachedAd.bannerView, null
                )

                if (success) {
                    AdConfigManager.getBannerConfig().recordShow()
                    if (!isCacheFull(finalPlacementId)) {
                        CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
                            try {
                                preloadAd(activity, finalPlacementId)
                            } catch (e: Exception) {
                                AdLogger.e("TopOn Banner 广告预加载失败", e)
                            }
                        }
                    }
                    AdResult.Success(cachedAd.bannerView)
                } else {
                    totalShowFailCount++
                    reportAdData(
                        eventName = "ad_show_fail",
                        params = mapOf(
                            "ad_unit_name" to finalPlacementId,
                            "position" to PositionGet.get(),
                            "number" to totalShowFailCount,
                            "reason" to "广告绑定失败"
                        )
                    )
                    AdResult.Failure(createAdException("广告绑定失败"))
                }
            } else {
                totalShowFailCount++
                reportAdData(
                    eventName = "ad_show_fail",
                    params = mapOf(
                        "ad_unit_name" to finalPlacementId,
                        "position" to PositionGet.get(),
                        "number" to totalShowFailCount,
                        "reason" to "No fill"
                    )
                )
                AdResult.Failure(createAdException("广告加载失败"))
            }
        } catch (e: Exception) {
            totalShowFailCount++
            reportAdData(
                eventName = "ad_show_fail",
                params = mapOf(
                    "ad_unit_name" to finalPlacementId,
                    "position" to PositionGet.get(),
                    "number" to totalShowFailCount,
                    "reason" to e.message.orEmpty()
                )
            )
            AdLogger.e("显示 TopOn Banner 广告失败", e)
            container.removeAllViews()
            AdResult.Failure(
                AdException(
                    code = -1,
                    message = "显示 Banner 广告异常: ${e.message}",
                    cause = e
                )
            )
        }
    }

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

    /**
     * 获取指定广告位的缓存数量
     */
    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
    }

    /**
     * 加载广告到缓存
     */
    suspend fun loadAdToCache(activity: Activity, 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 bannerView = loadAd(activity, placementId)
            if (bannerView != null) {
                synchronized(adCachePool) {
                    adCachePool.add(CachedBannerAd(bannerView, placementId))
                    val currentCount = getCachedAdCount(placementId)
                    AdLogger.d("TopOn Banner 广告加载成功并缓存，广告位ID: %s，该广告位缓存数量: %d/%d", placementId, currentCount, maxCacheSizePerAdUnit)
                }
                AdResult.Success(Unit)
            } else {
                AdResult.Failure(createAdException("广告加载失败"))
            }
        } catch (e: Exception) {
            AdLogger.e("TopOn Banner loadAdToCache异常", e)
            AdResult.Failure(AdException(0, "加载异常: ${e.message}", e))
        }
    }

    /**
     * 基础广告加载方法
     */
    private suspend fun loadAd(activity: Activity, placementId: String): TUBannerView? {
        // 累积加载次数统计
        totalLoadCount++
        AdLogger.d("TopOn Banner 广告开始加载，广告位ID: %s，当前累计加载次数: %d", placementId, totalLoadCount)

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

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

            try {
                val bannerView = TUBannerView(activity)
                bannerView.setPlacementId(placementId)

                val displayMetrics = activity.resources.displayMetrics
                val adWidth = displayMetrics.widthPixels
                val adHeight = (60 * displayMetrics.density).toInt()

                bannerView.layoutParams = ViewGroup.LayoutParams(adWidth, adHeight)

                // 设置监听器
                bannerView.setBannerAdListener(object : TUBannerListener {
                    override fun onBannerLoaded() {
                        val loadTime = System.currentTimeMillis() - startTime
                        totalLoadSucCount++

                        AdLogger.d("TopOn Banner 广告加载成功，广告位ID: %s, 耗时: %dms", placementId, loadTime)

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

                    override fun onBannerFailed(adError: AdError) {
                        val loadTime = System.currentTimeMillis() - startTime
                        AdLogger.e("TopOn Banner 广告加载失败，广告位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 onBannerClicked(adInfo: TUAdInfo) {
                        AdLogger.d("TopOn Banner 广告被点击")
                        currentAdInfo = adInfo

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

                        AdConfigManager.getBannerConfig().recordClick()

                        val revenueValue = adInfo.publisherRevenue ?: adInfo.ecpm ?: 0.0
                        val revenueCurrency = adInfo.currency ?: "USD"

                        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 revenueValue,
                                "currency" to revenueCurrency
                            )
                        )
                    }

                    override fun onBannerShow(adInfo: TUAdInfo) {
                        AdLogger.d("TopOn Banner 广告展示完成")
                        currentAdInfo = adInfo

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

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

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

                        reportAdRevenueWithValue(placementId, adInfo)
                    }

                    override fun onBannerClose(adInfo: TUAdInfo) {
                        AdLogger.d("TopOn Banner 广告关闭")
                        currentAdInfo = adInfo
                        totalCloseCount++

                        val revenueValue = adInfo.publisherRevenue ?: adInfo.ecpm ?: 0.0
                        val revenueCurrency = adInfo.currency ?: "USD"

                        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 revenueValue,
                                "currency" to revenueCurrency
                            )
                        )
                    }

                    override fun onBannerAutoRefreshed(adInfo: TUAdInfo) {
                        AdLogger.d("TopOn Banner 广告自动刷新")
                        currentAdInfo = adInfo
                    }

                    override fun onBannerAutoRefreshFail(adError: AdError) {
                        AdLogger.e("TopOn Banner 广告自动刷新失败: %s", adError.getFullErrorInfo())
                    }
                })

                val localExtra = mutableMapOf<String, Any>()
                localExtra[TUAdConst.KEY.AD_WIDTH] = adWidth
                localExtra[TUAdConst.KEY.AD_HEIGHT] = adHeight
                bannerView.setLocalExtra(localExtra)

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

    fun peekCachedAd(placementId: String = BuildConfig.TOPON_BANNER_ID): TUBannerView? {
        return synchronized(adCachePool) {
            adCachePool.firstOrNull { it.placementId == placementId && !it.isExpired() }?.bannerView
        }
    }

    fun getCurrentAd(placementId: String? = null): TUBannerView? {
        val finalPlacementId = placementId ?: BuildConfig.TOPON_BANNER_ID
        return peekCachedAd(finalPlacementId)
    }

    fun hasCachedAd(placementId: String? = null): Boolean {
        synchronized(adCachePool) {
            return if (placementId != null) {
                adCachePool.any { it.placementId == placementId && !it.isExpired() }
            } else {
                adCachePool.any { !it.isExpired() }
            }
        }
    }

    /**
     * 上报广告收益数据（使用真实收益值）
     * @param adInfo 广告信息
     */
    private fun reportAdRevenueWithValue(placementId: String, adInfo: TUAdInfo) {
        val revenueValue = adInfo.publisherRevenue ?: adInfo.ecpm ?: 0.0
        val revenueCurrency = adInfo.currency ?: "USD"

        // 创建广告收益数据
        val adRevenueData = AdRevenueData(
            revenue = RevenueInfo(
                value = revenueValue,
                currencyCode = revenueCurrency
            ),
            adRevenueNetwork = adInfo.networkName ?: "",
            adRevenueUnit = placementId,
            adRevenuePlacement = adInfo.placementId ?: "",
            adFormat = "Banner"
        )

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

    /**
     * 销毁广告
     */
    fun destroyAd() {
        synchronized(adCachePool) {
            adCachePool.forEach { cachedAd -> cachedAd.bannerView.destroy() }
            adCachePool.clear()
        }
        AdLogger.d("TopOn Banner 广告已销毁")
    }

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

    /**
     * 创建广告异常
     */
    private fun createAdException(message: String, cause: Throwable? = null): AdException {
        return AdException(
            code = -1,
            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 "Banner"
        )

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

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

