package com.composition.android.lib.ad.interfaces

import android.app.Activity
import android.content.Context
import android.view.View
import android.view.ViewGroup
import com.composition.android.lib.ad.AdManager
import com.composition.android.lib.ad.basic.*
import com.composition.android.lib.ad.bean.AdUnitBean
import com.composition.android.lib.ad.exception.AdLoadFailException
import com.composition.android.lib.ad.util.adLog
import com.composition.android.lib.ad.util.adLogE
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.withTimeoutOrNull

/**
 * @classname:
 * @author: LiuXiaoLong
 * @date: 2022/9/1
 * description:广告商加载广告接口
 */
interface AdLoader {

    val advertisers: Advertisers


    suspend fun load(context: Context, adUnitBean: AdUnitBean): AdResult


    /**
     * 广告根据策略配置进行加载
     * 可配置：
     * 加载超时时间、重试次数
     *
     */
    suspend fun loadByStrategy(context: Context, adUnitBean: AdUnitBean, iAdFormatRequest: IAdFormatRequest?): AdResult {
        if (iAdFormatRequest == null) {
            return AdResult.Fail(adUnitBean, msg = "广告类型解析出错，请检查adType, 当前广告商:${adUnitBean.advertisersName} 不支持 ${adUnitBean.adType} 类型的广告加载")
        }
        return try {
            withTimeoutOrNull(adUnitBean.requestAdConfig.adLoadTimeOut) {
                if (adUnitBean.requestAdConfig.adLoadRetryCount == 0){
                    return@withTimeoutOrNull iAdFormatRequest.load(context, adUnitBean)
                }else{
                    flow<AdResult> {
                        val result = iAdFormatRequest.load(context, adUnitBean)
                        emit(result)
                    }.onEach {
                        //这里判断如果加载失败了， 抛出加载失败异常
                        if (it is AdResult.Fail) {
                            throw AdLoadFailException()
                        }
                    }.retry(adUnitBean.requestAdConfig.adLoadRetryCount.toLong()) {
                        //判断如果是加载失败异常，进行重试
                        adLogE(tag = AdManager.TAG, msg = "【${adUnitBean.adSlotName}】-加载失败-进行重试")
                        it is AdLoadFailException
                    }.firstOrNull()
                }
            } ?: AdResult.Fail(adUnitBean, AdLoadCode.FAIL, "加载失败,请求结果为null")
        } catch (e: Exception) {
            e.printStackTrace()
            adLogE(tag = AdManager.TAG, msg = "【${adUnitBean.adSlotName}】加载失败-出现异常-${e.message}")
            AdResult.Fail(adUnitBean, AdLoadCode.FAIL, "加载失败-出现异常-${e.message}")
        }
    }

    /**
     * 获取BannerAd View
     */
    fun getBannerView(context: Context, adResult: AdResult.Success, viewHolder: BannerAdViewHolder): BasicAdView<*>?

    /**
     * 获取原生广告View
     *
     */
    fun getNativeAdView(context: Context, adResult: AdResult.Success, viewHolder: NativeAdViewHolder): View?

    /**
     * 销毁广告
     * 会根据adResult.adObject 类型调用destroy()进行销毁
     */
    fun destroyAd(adResult: AdResult)

    /**
     * 填充原生广告，不会返回View
     * @param adResult 请求成功的广告实例
     * @param viewHolder 要填充的广告布局内容
     * @param advertisersContainerView 厂商的广告容器view
     *
     * 例如: Admob原生广告最外层需要 com.google.android.gms.ads.nativead.NativeAdView 进行包裹自定义布局内容
     * advertisersContainerView 就传入这个NativeAdView
     *
     * Admob : com.google.android.gms.ads.nativead.NativeAdView
     * GroMore : com.bytedance.msdk.api.format.TTNativeAdView
     * CSJ : 不需要特定的布局， 随意ViewGroup都行
     *
     */
    fun populateNativeAdView(context: Context, adResult: AdResult.Success, viewHolder: NativeAdViewHolder, advertisersContainerView: ViewGroup)

    /**
     * 显示插屏广告
     */
    fun showInterstitialAd(activity: Activity, adResult: AdResult.Success, adListener: AdListener)

    /**
     * 显示激励视频广告
     */
    fun showRewardedAd(activity: Activity, adResult: AdResult.Success, adListener: AdListener)

    /**
     * 显示激励插屏广告
     */
    fun showRewardedInterstitialAd(activity: Activity, adResult: AdResult.Success, adListener: AdListener)

    /**
     * 显示开屏广告
     */
    fun showSplashAd(activity: Activity, splashViewGroup: ViewGroup?, adResult: AdResult.Success, adListener: AdListener)

    /**
     * 显示全屏广告
     * 会根据 adResult.adBean.adType判断是插屏、激励视频、激励插屏
     */
    fun showFullScreenAd(activity: Activity, adResult: AdResult.Success, adListener: AdListener)

}