package com.remax.bill.ads.topon

import android.content.Context
import android.view.ViewGroup
import com.blankj.utilcode.util.SizeUtils
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.ToponNativeAdStyle
import com.remax.bill.ui.topon.ToponNativeAdView
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.nativead.api.TUNative
import com.thinkup.nativead.api.TUNativeNetworkListener
import com.thinkup.nativead.api.NativeAd
import com.thinkup.nativead.api.TUNativeAdView
import com.thinkup.nativead.api.TUNativeDislikeListener
import com.thinkup.nativead.api.TUNativeEventListener
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原生广告控制器
 * 提供原生广告的加载和管理功能
 * 参考文档: https://help.toponad.net/cn/docs/yuan-sheng-guang-gao
 */
class TopOnNativeAdController private constructor() {
    
    // 累积点击统计（持久化）
    private var totalClickCount by KvIntDelegate("topon_native_ad_total_clicks", 0)

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

    // 累积加载成功次数统计（持久化）
    private var totalLoadSucCount by KvIntDelegate("topon_native_ad_total_load_suc", 0)
    
    // 累积展示失败次数统计（持久化）
    private var totalShowFailCount by KvIntDelegate("topon_native_ad_total_show_fails", 0)
    
    // 累积触发统计（持久化）
    private var totalShowTriggerCount by KvIntDelegate("topon_native_ad_total_show_triggers", 0)
    
    // 累积展示统计（持久化）
    private var totalShowCount by KvIntDelegate("topon_native_ad_total_shows", 0)
    
    companion object {
        private const val TAG = "ToponNativeAdController"
        private const val AD_TIMEOUT = 1 * 60 * 60 * 1000L // 1小时过期
        private const val DEFAULT_CACHE_SIZE_PER_AD_UNIT = 1
        
        @Volatile
        private var INSTANCE: TopOnNativeAdController? = null
        
        fun getInstance(): TopOnNativeAdController {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: TopOnNativeAdController().also { INSTANCE = it }
            }
        }
    }
    
    // 内存缓存池 - 存储预加载的广告
    private val adCachePool = mutableListOf<CachedNativeAd>()
    private val maxCacheSizePerAdUnit = DEFAULT_CACHE_SIZE_PER_AD_UNIT
    
    // 拦截器链
    private val interceptorChain = InterceptorChain(
        interceptors = listOf(
            GlobalAdSwitchInterceptor(),
            ShowCountLimitInterceptor(),
            ShowIntervalLimitInterceptor(),
            ClickLimitInterceptor()
        )
    )
    
    private val nativeAdView = ToponNativeAdView()
    
    // 当前广告的收益信息（临时存储）
    private var currentAdInfo: TUAdInfo? = null
    
    /**
     * 缓存的原生广告数据类
     */
    private data class CachedNativeAd(
        val ad: TUNative,
        val placementId: String,
        val loadTime: Long = System.currentTimeMillis()
    ) {
        fun isExpired(): Boolean {
            return System.currentTimeMillis() - loadTime > AD_TIMEOUT
        }
    }
    
    /**
     * 预加载原生广告（可选，用于提前准备）
     * @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_NATIVE_ID
        return loadAdToCache(context, finalPlacementId)
    }
    
    /**
     * 获取原生广告（自动处理加载）
     * @param context 上下文
     * @param placementId 广告位ID，如果为空则使用默认ID
     */
    suspend fun getAd(context: Context, placementId: String? = null): AdResult<TUNative> {
        val finalPlacementId = placementId ?: BuildConfig.TOPON_NATIVE_ID
        
        // 1. 尝试从缓存获取广告
        var cachedAd = getCachedAd(finalPlacementId)
        
        // 2. 如果缓存为空，立即加载并缓存一个广告
        if (cachedAd == null) {
            AdLogger.d("缓存为空，立即加载TopOn原生广告，广告位ID: %s", finalPlacementId)
            loadAdToCache(context, finalPlacementId)
            cachedAd = getCachedAd(finalPlacementId)
        }
        
        return if (cachedAd != null) {
            AdLogger.d("使用缓存中的TopOn原生广告，广告位ID: %s", finalPlacementId)
            AdResult.Success(cachedAd.ad)
        } else {
            AdResult.Failure(createAdException("广告加载失败"))
        }
    }
    
    /**
     * 显示原生广告到指定容器（简化版接口）
     * @param context 上下文
     * @param container 目标容器
     * @param style 广告样式，默认为标准样式
     * @param placementId 广告位ID，如果为空则使用默认ID
     * @return 是否显示成功
     */
    suspend fun showAdInContainer(
        context: Context, 
        container: ViewGroup,
        style: ToponNativeAdStyle = ToponNativeAdStyle.STANDARD,
        placementId: String? = null
    ): Boolean {
        val finalPlacementId = placementId ?: BuildConfig.TOPON_NATIVE_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(context, AdConfigManager.getNativeConfig())) {
            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
                    )
                )
                
                AdLogger.w("TopOn原生广告拦截器检查失败: %s", interceptResult.error.message)
                return false
            }
            else -> { /* continue */ }
        }
        
        return try {
            when (val result = getAd(context, placementId)) {
                is AdResult.Success -> {
                    val tuNative = result.data
                    val nativeAd = tuNative.getNativeAd()
                    if (nativeAd == null) {
                        AdLogger.e("TopOn原生广告获取NativeAd失败")
                        return false
                    }
                    // 设置事件监听器
                    nativeAd.setNativeEventListener(createNativeEventListener(finalPlacementId, nativeAd))
                    // 当有显示关闭按钮时点击回调，并非关闭弹出的页面
                    nativeAd.setDislikeCallbackListener(object :TUNativeDislikeListener(){
                        override fun onAdCloseButtonClick(
                            p0: TUNativeAdView?,
                            adInfo: TUAdInfo
                        ) {
                            AdLogger.d("TopOn原生广告关闭")
                            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 finalPlacementId,
                                    "position" to PositionGet.get(),
                                    "number" to totalCloseCount,
                                    "ad_source" to (adInfo.networkName ?: ""),
                                    "value" to revenueValue,
                                    "currency" to revenueCurrency
                                )
                            )
                        }
                    })
                    // 设置容器高度（如果style指定了高度）
                    if (style.heightDp > 0) {
                        val heightPx = SizeUtils.dp2px(style.heightDp.toFloat())
                        container.layoutParams = container.layoutParams?.apply {
                            height = heightPx
                        }
                    }
                    // 绑定广告到容器
                    nativeAdView.bindNativeAdToContainer(context, container, nativeAd, style)
                    true
                }
                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 result.error.message
                        )
                    )
                    false
                }
                AdResult.Loading -> {
                    // 保持加载状态
                    false
                }
            }
        } catch (e: Exception) {
            // 累积展示失败次数统计
            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 "${e.message}"
                )
            )
            
            AdLogger.e("显示TopOn原生广告失败", e)
            false
        }
    }
    
    /**
     * 基础广告加载方法（可复用）
     */
    private suspend fun loadAd(context: Context, placementId: String): TUNative? {
        // 累积加载次数统计
        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 ->
            val startTime = System.currentTimeMillis()
            val applicationContext = context.applicationContext
            
            // 将 tuNative 定义在外部作用域，以便在回调中访问
            var tuNative: TUNative? = null
            
            try {
                tuNative = TUNative(applicationContext, placementId, object : TUNativeNetworkListener {
                    override fun onNativeAdLoaded() {
                        val loadTime = System.currentTimeMillis() - startTime
                        totalLoadSucCount++
                        
                        AdLogger.d("TopOn原生广告加载成功，广告位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()
                            )
                        )

                        // 直接返回 TUNative
                        continuation.resume(tuNative)
                    }
                    
                    override fun onNativeAdLoadFail(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)
                    }
                })

                // 发起广告请求
                tuNative.makeAdRequest()
            } catch (e: Exception) {
                AdLogger.e("TopOn原生广告加载异常", e)
                if (continuation.isActive) {
                    continuation.resume(null)
                }
            }
        }
    }
    
    /**
     * 创建原生广告事件监听器
     */
    private fun createNativeEventListener(
        placementId: String,
        nativeAd: NativeAd
    ): TUNativeEventListener {
        return object : TUNativeEventListener {
            override fun onAdImpressed(view: com.thinkup.nativead.api.TUNativeAdView, adInfo: TUAdInfo) {
                AdLogger.d("TopOn原生广告展示完成")
                currentAdInfo = adInfo
                
                // 累积展示统计
                totalShowCount++
                AdLogger.d("TopOn原生广告累积展示次数: $totalShowCount")
                
                // 记录展示
                AdConfigManager.getNativeConfig().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
                    )
                )
                
                // TopOn 的 revenueValue 已经是美元，不需要转换
                val revenueUsd = revenueValue.toLong()
                
                reportAdRevenueWithValue(placementId, adInfo)

                // 异步预加载下一个广告到缓存（如果缓存未满）
                if (!isCacheFull(placementId)) {
                    CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
                        try {
                            preloadAd(view.context, placementId)
                        } catch (e: Exception) {
                            AdLogger.e("TopOn原生广告预加载失败", e)
                        }
                    }
                }
            }
            
            override fun onAdClicked(view: com.thinkup.nativead.api.TUNativeAdView, adInfo: TUAdInfo) {
                AdLogger.d("TopOn原生广告被点击")
                currentAdInfo = adInfo
                
                // 累积点击统计
                totalClickCount++
                AdLogger.d("TopOn原生广告累积点击次数: $totalClickCount")
                
                AdConfigManager.getNativeConfig().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 onAdVideoStart(p0: TUNativeAdView?) {
            }

            override fun onAdVideoEnd(p0: TUNativeAdView?) {
            }

            override fun onAdVideoProgress(
                p0: TUNativeAdView?,
                p1: Int
            ) {
            }

            fun onAdClosed(view: com.thinkup.nativead.api.TUNativeAdView, adInfo: TUAdInfo) {

            }
        }
    }
    
    /**
     * 加载广告到缓存
     */
    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 tuNative = loadAd(context, placementId)
            if (tuNative != null) {
                synchronized(adCachePool) {
                    adCachePool.add(CachedNativeAd(tuNative, 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))
        }
    }
    
    fun peekCachedAd(placementId: String = BuildConfig.TOPON_NATIVE_ID): TUNative? {
        return synchronized(adCachePool) {
            adCachePool.firstOrNull { it.placementId == placementId && !it.isExpired() }?.ad
        }
    }

    /**
     * 从缓存获取广告
     */
    private fun getCachedAd(placementId: String): CachedNativeAd? {
        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
    }
    
    /**
     * 获取当前加载的广告数据
     */
    fun getCurrentAd(): TUNative? {
        return getCachedAd(BuildConfig.TOPON_NATIVE_ID)?.ad
    }
    
    /**
     * 检查是否有可用的广告
     */
    fun isAdLoaded(): Boolean {
        return getCachedAdCount(BuildConfig.TOPON_NATIVE_ID) > 0
    }
    
    /**
     * 销毁广告
     */
    fun destroyAd() {
        synchronized(adCachePool) {
            adCachePool.forEach { cachedAd ->
                // TopOn 原生广告不需要显式销毁
            }
            adCachePool.clear()
        }
        AdLogger.d("TopOn原生广告已销毁")
    }
    
    /**
     * 上报广告收益数据（使用真实收益值）
     * @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.scenarioId ?: "",
            adFormat = "Native"
        )
        
        // 上报收益数据（内部已处理初始化和异常）
        AdRevenueManager.reportAdRevenue(adRevenueData)
        AdLogger.d("TopOn原生广告真实收益数据已上报，广告位ID: ${placementId}, 收益: %.8f %s", revenueValue, revenueCurrency)
    }
    
    /**
     * 清理资源
     */
    fun destroy() {
        destroyAd()
        AdLogger.d("TopOn原生广告控制器已清理")
    }
    
    /**
     * 通用数据上报函数
     * @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 "Native"
        )
        
        // 直接合并传入的参数
        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
        )
    }
}

